gnuplot-iostream.h
Go to the documentation of this file.
1 /*
2 Copyright (c) 2013 Daniel Stahlke (dan@stahlke.org)
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 /* A C++ interface to gnuplot.
24  * Web page: http://www.stahlke.org/dan/gnuplot-iostream
25  * Documentation: https://github.com/dstahlke/gnuplot-iostream/wiki
26  *
27  * The whole library consists of this monolithic header file, for ease of installation (the
28  * Makefile and *.cc files are only for examples and tests).
29  *
30  * TODO:
31  * What version of boost is currently required?
32  * Callbacks via gnuplot's 'bind' function. This would allow triggering user functions when
33  * keys are pressed in the gnuplot window. However, it would require a PTY reader thread.
34  * Maybe temporary files read in a thread can replace PTY stuff.
35  */
36 
37 #ifndef GNUPLOT_IOSTREAM_H
38 #define GNUPLOT_IOSTREAM_H
39 
40 // {{{1 Includes and defines
41 
42 #define GNUPLOT_IOSTREAM_VERSION 2
43 
44 #ifndef GNUPLOT_ENABLE_CXX11
45 # define GNUPLOT_ENABLE_CXX11 (__cplusplus >= 201103)
46 #endif
47 
48 // C system includes
49 #include <cstdio>
50 #ifdef GNUPLOT_ENABLE_PTY
51 # include <termios.h>
52 # include <unistd.h>
53 #ifdef __APPLE__
54 # include <util.h>
55 #else
56 # include <pty.h>
57 #endif
58 #endif // GNUPLOT_ENABLE_PTY
59 
60 // C++ system includes
61 #include <fstream>
62 #include <iostream>
63 #include <sstream>
64 #include <stdexcept>
65 #include <string>
66 #include <utility>
67 #include <iomanip>
68 #include <vector>
69 #include <complex>
70 #include <cstdlib>
71 #include <cmath>
72 
73 #if GNUPLOT_ENABLE_CXX11
74 # include <tuple>
75 #endif
76 
77 #include <boost/iostreams/device/file_descriptor.hpp>
78 #include <boost/iostreams/stream.hpp>
79 #include <boost/version.hpp>
80 #include <boost/utility.hpp>
81 #include <boost/tuple/tuple.hpp>
82 #include <boost/mpl/bool.hpp>
83 // This is the version of boost which has v3 of the filesystem libraries by default.
84 #if BOOST_VERSION >= 104600
85 # define GNUPLOT_USE_TMPFILE
86 # include <boost/filesystem.hpp>
87 #endif // BOOST_VERSION
88 
89 // This is used because VS2008 doesn't have stdint.h.
90 #include <boost/cstdint.hpp>
91 
92 // Note: this is here for reverse compatibility. The new way to enable blitz support is to
93 // just include the gnuplot-iostream.h header after you include the blitz header (likewise for
94 // armadillo).
95 #ifdef GNUPLOT_ENABLE_BLITZ
96 # include <blitz/array.h>
97 #endif
98 
99 #ifdef BOOST_STATIC_ASSERT_MSG
100 # define GNUPLOT_STATIC_ASSERT_MSG(cond, msg) BOOST_STATIC_ASSERT_MSG((cond), msg)
101 #else
102 # define GNUPLOT_STATIC_ASSERT_MSG(cond, msg) BOOST_STATIC_ASSERT((cond))
103 #endif
104 
105 // If this is defined, warn about use of deprecated functions.
106 #ifdef GNUPLOT_DEPRECATE_WARN
107 # ifdef __GNUC__
108 # define GNUPLOT_DEPRECATE(msg) __attribute__ ((deprecated(msg)))
109 # elif defined(_MSC_VER)
110 # define GNUPLOT_DEPRECATE(msg) __declspec(deprecated(msg))
111 # else
112 # define GNUPLOT_DEPRECATE(msg)
113 # endif
114 #else
115 # define GNUPLOT_DEPRECATE(msg)
116 #endif
117 
118 // Patch for Windows by Damien Loison
119 #ifdef _WIN32
120 # include <windows.h>
121 # define GNUPLOT_PCLOSE _pclose
122 # define GNUPLOT_POPEN _popen
123 # define GNUPLOT_FILENO _fileno
124 #else
125 # define GNUPLOT_PCLOSE pclose
126 # define GNUPLOT_POPEN popen
127 # define GNUPLOT_FILENO fileno
128 #endif
129 
130 #ifdef _WIN32
131 # define GNUPLOT_ISNAN _isnan
132 #else
133 // cppreference.com says std::isnan is only for C++11. However, this seems to work on Linux
134 // and I am assuming that if isnan exists in math.h then std::isnan exists in cmath.
135 # define GNUPLOT_ISNAN std::isnan
136 #endif
137 
138 // MSVC gives a warning saying that fopen and getenv are not secure. But they are secure.
139 // Unfortunately their replacement functions are not simple drop-in replacements. The best
140 // solution is to just temporarily disable this warning whenever fopen or getenv is used.
141 // http://stackoverflow.com/a/4805353/1048959
142 #if defined(_MSC_VER) && _MSC_VER >= 1400
143 # define GNUPLOT_MSVC_WARNING_4996_PUSH \
144  __pragma(warning(push)) \
145  __pragma(warning(disable:4996))
146 # define GNUPLOT_MSVC_WARNING_4996_POP \
147  __pragma(warning(pop))
148 #else
149 # define GNUPLOT_MSVC_WARNING_4996_PUSH
150 # define GNUPLOT_MSVC_WARNING_4996_POP
151 #endif
152 
153 #ifndef GNUPLOT_DEFAULT_COMMAND
154 #ifdef _WIN32
155 // "pgnuplot" is considered deprecated according to the Internet. It may be faster. It
156 // doesn't seem to handle binary data though.
157 //# define GNUPLOT_DEFAULT_COMMAND "pgnuplot -persist"
158 // On Windows, gnuplot echos commands to stderr. So we forward its stderr to the bit bucket.
159 // Unfortunately, this means you will miss out on legitimate error messages.
160 # define GNUPLOT_DEFAULT_COMMAND "gnuplot -persist 2> NUL"
161 #else
162 # define GNUPLOT_DEFAULT_COMMAND "gnuplot -persist"
163 #endif
164 #endif
165 
166 // }}}1
167 
168 namespace gnuplotio {
169 
170 // {{{1 Basic traits helpers
171 //
172 // The mechanisms constructed in this section enable us to detect what sort of datatype has
173 // been passed to a function.
174 
175 // This can be specialized as needed, in order to not use the STL interfaces for specific
176 // classes.
177 template <typename T>
179  typedef boost::mpl::bool_<false> type;
180 };
181 
182 BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type)
183 BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
184 
185 template <typename T>
187  typedef boost::mpl::and_<
188  typename has_value_type<T>::type,
189  typename has_const_iterator<T>::type,
190  boost::mpl::not_<dont_treat_as_stl_container<T> >
191  > type;
192  static const bool value = type::value;
193 };
194 
195 template <typename T>
197  static const bool value = false;
198  typedef boost::mpl::bool_<value> type;
199 };
200 
201 template <>
202 struct is_boost_tuple_nulltype<boost::tuples::null_type> {
203  static const bool value = true;
204  typedef boost::mpl::bool_<value> type;
205 };
206 
207 BOOST_MPL_HAS_XXX_TRAIT_DEF(head_type)
208 BOOST_MPL_HAS_XXX_TRAIT_DEF(tail_type)
209 
210 template <typename T>
212  typedef boost::mpl::and_<
213  typename has_head_type<T>::type,
214  typename has_tail_type<T>::type
215  > type;
216  static const bool value = type::value;
217 };
218 
219 // More fine-grained, but doesn't compile!
220 //template <typename T>
221 //struct is_boost_tuple {
222 // typedef boost::mpl::and_<
223 // typename boost::is_class<T>::type,
224 // typename boost::mpl::and_<
225 // typename has_head_type<T>::type,
226 // typename boost::mpl::and_<
227 // typename has_tail_type<T>::type,
228 // typename boost::mpl::or_<
229 // typename is_boost_tuple_nulltype<typename T::tail_type>::type,
230 // typename is_boost_tuple<typename T::tail_type>::type
231 // >::type
232 // >::type
233 // >::type
234 // > type;
235 //};
236 //
237 //template <>
238 //struct is_boost_tuple<boost::tuples::null_type> {
239 // typedef boost::mpl::bool_<false> type;
240 //};
241 
242 // }}}1
243 
244 // {{{1 Tmpfile helper class
245 #ifdef GNUPLOT_USE_TMPFILE
246 // RAII temporary file. File is removed when this object goes out of scope.
247 class GnuplotTmpfile {
248 public:
249  GnuplotTmpfile() :
250  file(boost::filesystem::unique_path(
251  boost::filesystem::temp_directory_path() /
252  "tmp-gnuplot-%%%%-%%%%-%%%%-%%%%"))
253  { }
254 
255 private:
256  // noncopyable
257  GnuplotTmpfile(const GnuplotTmpfile &);
258  const GnuplotTmpfile& operator=(const GnuplotTmpfile &);
259 
260 public:
261  ~GnuplotTmpfile() {
262  // it is never good to throw exceptions from a destructor
263  try {
264  remove(file);
265  } catch(const std::exception &) {
266  std::cerr << "Failed to remove temporary file " << file << std::endl;
267  }
268  }
269 
270 public:
271  boost::filesystem::path file;
272 };
273 #endif // GNUPLOT_USE_TMPFILE
274 // }}}1
275 
276 // {{{1 Feedback helper classes
277 //
278 // Used for reading stuff sent from gnuplot via gnuplot's "print" function.
279 //
280 // For example, this is used for capturing mouse clicks in the gnuplot window. There are two
281 // implementations, only the first of which is complete. The first implementation allocates a
282 // PTY (pseudo terminal) which is written to by gnuplot and read by us. This only works in
283 // Linux. The second implementation creates a temporary file which is written to by gnuplot
284 // and read by us. However, this doesn't currently work since fscanf doesn't block. It would
285 // be possible to get this working using a more complicated mechanism (select or threads) but I
286 // haven't had the need for it.
287 
289 public:
291  virtual ~GnuplotFeedback() { }
292  virtual std::string filename() const = 0;
293  virtual FILE *handle() const = 0;
294 
295 private:
296  // noncopyable
298  const GnuplotFeedback& operator=(const GnuplotFeedback &);
299 };
300 
301 #ifdef GNUPLOT_ENABLE_PTY
302 #define GNUPLOT_ENABLE_FEEDBACK
303 class GnuplotFeedbackPty : public GnuplotFeedback {
304 public:
305  explicit GnuplotFeedbackPty(bool debug_messages) :
306  pty_fn(),
307  pty_fh(NULL),
308  master_fd(-1),
309  slave_fd(-1)
310  {
311  // adapted from http://www.gnuplot.info/files/gpReadMouseTest.c
312  if(0 > openpty(&master_fd, &slave_fd, NULL, NULL, NULL)) {
313  perror("openpty");
314  throw std::runtime_error("openpty failed");
315  }
316  char pty_fn_buf[1024];
317  if(ttyname_r(slave_fd, pty_fn_buf, 1024)) {
318  perror("ttyname_r");
319  throw std::runtime_error("ttyname failed");
320  }
321  pty_fn = std::string(pty_fn_buf);
322  if(debug_messages) {
323  std::cerr << "feedback_fn=" << pty_fn << std::endl;
324  }
325 
326  // disable echo
327  struct termios tios;
328  if(tcgetattr(slave_fd, &tios) < 0) {
329  perror("tcgetattr");
330  throw std::runtime_error("tcgetattr failed");
331  }
332  tios.c_lflag &= ~(ECHO | ECHONL);
333  if(tcsetattr(slave_fd, TCSAFLUSH, &tios) < 0) {
334  perror("tcsetattr");
335  throw std::runtime_error("tcsetattr failed");
336  }
337 
338  pty_fh = fdopen(master_fd, "r");
339  if(!pty_fh) {
340  throw std::runtime_error("fdopen failed");
341  }
342  }
343 
344 private:
345  // noncopyable
346  GnuplotFeedbackPty(const GnuplotFeedbackPty &);
347  const GnuplotFeedbackPty& operator=(const GnuplotFeedbackPty &);
348 
349 public:
350  ~GnuplotFeedbackPty() {
351  if(pty_fh) fclose(pty_fh);
352  if(master_fd > 0) ::close(master_fd);
353  if(slave_fd > 0) ::close(slave_fd);
354  }
355 
356  std::string filename() const {
357  return pty_fn;
358  }
359 
360  FILE *handle() const {
361  return pty_fh;
362  }
363 
364 private:
365  std::string pty_fn;
366  FILE *pty_fh;
367  int master_fd, slave_fd;
368 };
369 //#elif defined GNUPLOT_USE_TMPFILE
371 //#define GNUPLOT_ENABLE_FEEDBACK
372 //class GnuplotFeedbackTmpfile : public GnuplotFeedback {
373 //public:
374 // explicit GnuplotFeedbackTmpfile(bool debug_messages) :
375 // tmp_file(),
376 // fh(NULL)
377 // {
378 // if(debug_messages) {
379 // std::cerr << "feedback_fn=" << filename() << std::endl;
380 // }
381 // GNUPLOT_MSVC_WARNING_4996_PUSH
382 // fh = std::fopen(filename().c_str(), "a");
383 // GNUPLOT_MSVC_WARNING_4996_POP
384 // }
385 //
386 // ~GnuplotFeedbackTmpfile() {
387 // fclose(fh);
388 // }
389 //
390 //private:
391 // // noncopyable
392 // GnuplotFeedbackTmpfile(const GnuplotFeedbackTmpfile &);
393 // const GnuplotFeedbackTmpfile& operator=(const GnuplotFeedbackTmpfile &);
394 //
395 //public:
396 // std::string filename() const {
397 // return tmp_file.file.string();
398 // }
399 //
400 // FILE *handle() const {
401 // return fh;
402 // }
403 //
404 //private:
405 // GnuplotTmpfile tmp_file;
406 // FILE *fh;
407 //};
408 #endif // GNUPLOT_ENABLE_PTY, GNUPLOT_USE_TMPFILE
409 // }}}1
410 
411 // {{{1 Traits and printers for entry datatypes
412 //
413 // This section contains the mechanisms for sending scalar and tuple data to gnuplot. Pairs
414 // and tuples are sent by appealing to the senders defined for their component scalar types.
415 // Senders for arrays are defined in a later section.
416 //
417 // There are three classes which need to be specialized for each supported datatype:
418 // 1. TextSender to send data as text. The default is to just send using the ostream's `<<`
419 // operator.
420 // 2. BinarySender to send data as binary, in a format which gnuplot can understand. There is
421 // no default implementation (unimplemented types raise a compile time error), however
422 // inheriting from FlatBinarySender will send the data literally as it is stored in memory.
423 // This suffices for most of the standard built-in types (e.g. uint32_t or double).
424 // 3. BinfmtSender sends a description of the data format to gnuplot (e.g. `%uint32`). Type
425 // `show datafile binary datasizes` in gnuplot to see a list of supported formats.
426 
427 // {{{2 Basic entry datatypes
428 
429 // Default TextSender, sends data using `<<` operator.
430 template <typename T, typename Enable=void>
431 struct TextSender {
432  static void send(std::ostream &stream, const T &v) {
433  stream << v;
434  }
435 };
436 
437 // Default BinarySender, raises a compile time error.
438 template <typename T, typename Enable=void>
439 struct BinarySender {
440  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "BinarySender class not specialized for this type");
441 
442  // This is here to avoid further compilation errors, beyond what the assert prints.
443  static void send(std::ostream &stream, const T &v);
444 };
445 
446 // This is a BinarySender implementation that just sends directly from memory. Data types
447 // which can be sent this way can have their BinarySender specialization inherit from this.
448 template <typename T>
450  static void send(std::ostream &stream, const T &v) {
451  stream.write(reinterpret_cast<const char *>(&v), sizeof(T));
452  }
453 };
454 
455 // Default BinfmtSender, raises a compile time error.
456 template <typename T, typename Enable=void>
457 struct BinfmtSender {
458  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "BinfmtSender class not specialized for this type");
459 
460  // This is here to avoid further compilation errors, beyond what the assert prints.
461  static void send(std::ostream &);
462 };
463 
464 // BinfmtSender implementations for basic data types supported by gnuplot.
465 // Types from boost/cstdint.hpp are used because VS2008 doesn't have stdint.h.
466 template<> struct BinfmtSender< float> { static void send(std::ostream &stream) { stream << "%float"; } };
467 template<> struct BinfmtSender<double> { static void send(std::ostream &stream) { stream << "%double"; } };
468 template<> struct BinfmtSender<boost:: int8_t> { static void send(std::ostream &stream) { stream << "%int8"; } };
469 template<> struct BinfmtSender<boost:: uint8_t> { static void send(std::ostream &stream) { stream << "%uint8"; } };
470 template<> struct BinfmtSender<boost:: int16_t> { static void send(std::ostream &stream) { stream << "%int16"; } };
471 template<> struct BinfmtSender<boost::uint16_t> { static void send(std::ostream &stream) { stream << "%uint16"; } };
472 template<> struct BinfmtSender<boost:: int32_t> { static void send(std::ostream &stream) { stream << "%int32"; } };
473 template<> struct BinfmtSender<boost::uint32_t> { static void send(std::ostream &stream) { stream << "%uint32"; } };
474 template<> struct BinfmtSender<boost:: int64_t> { static void send(std::ostream &stream) { stream << "%int64"; } };
475 template<> struct BinfmtSender<boost::uint64_t> { static void send(std::ostream &stream) { stream << "%uint64"; } };
476 
477 // BinarySender implementations for basic data types supported by gnuplot. These types can
478 // just be sent as stored in memory, so all these senders inherit from FlatBinarySender.
479 template<> struct BinarySender< float> : public FlatBinarySender< float> { };
480 template<> struct BinarySender<double> : public FlatBinarySender<double> { };
481 template<> struct BinarySender<boost:: int8_t> : public FlatBinarySender<boost:: int8_t> { };
482 template<> struct BinarySender<boost:: uint8_t> : public FlatBinarySender<boost:: uint8_t> { };
483 template<> struct BinarySender<boost:: int16_t> : public FlatBinarySender<boost:: int16_t> { };
484 template<> struct BinarySender<boost::uint16_t> : public FlatBinarySender<boost::uint16_t> { };
485 template<> struct BinarySender<boost:: int32_t> : public FlatBinarySender<boost:: int32_t> { };
486 template<> struct BinarySender<boost::uint32_t> : public FlatBinarySender<boost::uint32_t> { };
487 template<> struct BinarySender<boost:: int64_t> : public FlatBinarySender<boost:: int64_t> { };
488 template<> struct BinarySender<boost::uint64_t> : public FlatBinarySender<boost::uint64_t> { };
489 
490 // Make char types print as integers, not as characters.
491 template <typename T>
493  static void send(std::ostream &stream, const T &v) {
494  stream << int(v);
495  }
496 };
497 template<> struct TextSender< char> : public CastIntTextSender< char> { };
498 template<> struct TextSender< signed char> : public CastIntTextSender< signed char> { };
499 template<> struct TextSender< unsigned char> : public CastIntTextSender< unsigned char> { };
500 
501 // Make sure that the same not-a-number string is printed on all platforms.
502 template <typename T>
504  static void send(std::ostream &stream, const T &v) {
505  if(GNUPLOT_ISNAN(v)) { stream << "nan"; } else { stream << v; }
506  }
507 };
508 template<> struct TextSender< float> : FloatTextSender< float> { };
509 template<> struct TextSender< double> : FloatTextSender< double> { };
510 template<> struct TextSender<long double> : FloatTextSender<long double> { };
511 
512 // }}}2
513 
514 // {{{2 std::pair support
515 
516 template <typename T, typename U>
517 struct TextSender<std::pair<T, U> > {
518  static void send(std::ostream &stream, const std::pair<T, U> &v) {
519  TextSender<T>::send(stream, v.first);
520  stream << " ";
521  TextSender<U>::send(stream, v.second);
522  }
523 };
524 
525 template <typename T, typename U>
526 struct BinfmtSender<std::pair<T, U> > {
527  static void send(std::ostream &stream) {
528  BinfmtSender<T>::send(stream);
529  BinfmtSender<U>::send(stream);
530  }
531 };
532 
533 template <typename T, typename U>
534 struct BinarySender<std::pair<T, U> > {
535  static void send(std::ostream &stream, const std::pair<T, U> &v) {
536  BinarySender<T>::send(stream, v.first);
537  BinarySender<U>::send(stream, v.second);
538  }
539 };
540 
541 // }}}2
542 
543 // {{{2 std::complex support
544 
545 template <typename T>
546 struct TextSender<std::complex<T> > {
547  static void send(std::ostream &stream, const std::complex<T> &v) {
548  TextSender<T>::send(stream, v.real());
549  stream << " ";
550  TextSender<T>::send(stream, v.imag());
551  }
552 };
553 
554 template <typename T>
555 struct BinfmtSender<std::complex<T> > {
556  static void send(std::ostream &stream) {
557  BinfmtSender<T>::send(stream);
558  BinfmtSender<T>::send(stream);
559  }
560 };
561 
562 template <typename T>
563 struct BinarySender<std::complex<T> > {
564  static void send(std::ostream &stream, const std::complex<T> &v) {
565  BinarySender<T>::send(stream, v.real());
566  BinarySender<T>::send(stream, v.imag());
567  }
568 };
569 
570 // }}}2
571 
572 // {{{2 boost::tuple support
573 
574 template <typename T>
575 struct TextSender<T,
576  typename boost::enable_if<
577  boost::mpl::and_<
578  is_boost_tuple<T>,
579  boost::mpl::not_<is_boost_tuple_nulltype<typename T::tail_type> >
580  >
581  >::type
582 > {
583  static void send(std::ostream &stream, const T &v) {
584  TextSender<typename T::head_type>::send(stream, v.get_head());
585  stream << " ";
586  TextSender<typename T::tail_type>::send(stream, v.get_tail());
587  }
588 };
589 
590 template <typename T>
591 struct TextSender<T,
592  typename boost::enable_if<
593  boost::mpl::and_<
594  is_boost_tuple<T>,
595  is_boost_tuple_nulltype<typename T::tail_type>
596  >
597  >::type
598 > {
599  static void send(std::ostream &stream, const T &v) {
600  TextSender<typename T::head_type>::send(stream, v.get_head());
601  }
602 };
603 
604 template <typename T>
605 struct BinfmtSender<T,
606  typename boost::enable_if<
607  boost::mpl::and_<
608  is_boost_tuple<T>,
609  boost::mpl::not_<is_boost_tuple_nulltype<typename T::tail_type> >
610  >
611  >::type
612 > {
613  static void send(std::ostream &stream) {
615  stream << " ";
617  }
618 };
619 
620 template <typename T>
621 struct BinfmtSender<T,
622  typename boost::enable_if<
623  boost::mpl::and_<
624  is_boost_tuple<T>,
625  is_boost_tuple_nulltype<typename T::tail_type>
626  >
627  >::type
628 > {
629  static void send(std::ostream &stream) {
631  }
632 };
633 
634 template <typename T>
635 struct BinarySender<T,
636  typename boost::enable_if<
637  boost::mpl::and_<
638  is_boost_tuple<T>,
639  boost::mpl::not_<is_boost_tuple_nulltype<typename T::tail_type> >
640  >
641  >::type
642 > {
643  static void send(std::ostream &stream, const T &v) {
644  BinarySender<typename T::head_type>::send(stream, v.get_head());
645  BinarySender<typename T::tail_type>::send(stream, v.get_tail());
646  }
647 };
648 
649 template <typename T>
650 struct BinarySender<T,
651  typename boost::enable_if<
652  boost::mpl::and_<
653  is_boost_tuple<T>,
654  is_boost_tuple_nulltype<typename T::tail_type>
655  >
656  >::type
657 > {
658  static void send(std::ostream &stream, const T &v) {
659  BinarySender<typename T::head_type>::send(stream, v.get_head());
660  }
661 };
662 
663 // }}}2
664 
665 // {{{2 std::tuple support
666 
667 #if GNUPLOT_ENABLE_CXX11
668 
669 // http://stackoverflow.com/questions/6245735/pretty-print-stdtuple
670 
671 template<std::size_t> struct int_{}; // compile-time counter
672 
673 template <typename Tuple, std::size_t I>
674 void std_tuple_formatcode_helper(std::ostream &stream, const Tuple *, int_<I>) {
675  std_tuple_formatcode_helper(stream, (const Tuple *)(0), int_<I-1>());
676  stream << " ";
678 }
679 
680 template <typename Tuple>
681 void std_tuple_formatcode_helper(std::ostream &stream, const Tuple *, int_<0>) {
683 }
684 
685 template <typename... Args>
686 struct BinfmtSender<std::tuple<Args...> > {
687  typedef typename std::tuple<Args...> Tuple;
688 
689  static void send(std::ostream &stream) {
690  std_tuple_formatcode_helper(stream, (const Tuple *)(0), int_<sizeof...(Args)-1>());
691  }
692 };
693 
694 template <typename Tuple, std::size_t I>
695 void std_tuple_textsend_helper(std::ostream &stream, const Tuple &v, int_<I>) {
696  std_tuple_textsend_helper(stream, v, int_<I-1>());
697  stream << " ";
698  TextSender<typename std::tuple_element<I, Tuple>::type>::send(stream, std::get<I>(v));
699 }
700 
701 template <typename Tuple>
702 void std_tuple_textsend_helper(std::ostream &stream, const Tuple &v, int_<0>) {
703  TextSender<typename std::tuple_element<0, Tuple>::type>::send(stream, std::get<0>(v));
704 }
705 
706 template <typename... Args>
707 struct TextSender<std::tuple<Args...> > {
708  typedef typename std::tuple<Args...> Tuple;
709 
710  static void send(std::ostream &stream, const Tuple &v) {
711  std_tuple_textsend_helper(stream, v, int_<sizeof...(Args)-1>());
712  }
713 };
714 
715 template <typename Tuple, std::size_t I>
716 void std_tuple_binsend_helper(std::ostream &stream, const Tuple &v, int_<I>) {
717  std_tuple_binsend_helper(stream, v, int_<I-1>());
718  BinarySender<typename std::tuple_element<I, Tuple>::type>::send(stream, std::get<I>(v));
719 }
720 
721 template <typename Tuple>
722 void std_tuple_binsend_helper(std::ostream &stream, const Tuple &v, int_<0>) {
723  BinarySender<typename std::tuple_element<0, Tuple>::type>::send(stream, std::get<0>(v));
724 }
725 
726 template <typename... Args>
727 struct BinarySender<std::tuple<Args...> > {
728  typedef typename std::tuple<Args...> Tuple;
729 
730  static void send(std::ostream &stream, const Tuple &v) {
731  std_tuple_binsend_helper(stream, v, int_<sizeof...(Args)-1>());
732  }
733 };
734 
735 #endif // GNUPLOT_ENABLE_CXX11
736 
737 // }}}2
738 
739 // }}}1
740 
741 // {{{1 ArrayTraits and Range classes
742 //
743 // This section handles sending of array data to gnuplot. It is rather complicated because of
744 // the diversity of storage schemes supported. For example, it treats a
745 // `std::pair<std::vector<T>, std::vector<U>>` in the same way as a
746 // `std::vector<std::pair<T, U>>`, iterating through the two arrays in lockstep, and sending
747 // pairs <T,U> to gnuplot as columns. In fact, any nested combination of pairs, tuples, STL
748 // containers, Blitz arrays, and Armadillo arrays is supported (with the caveat that, for
749 // instance, Blitz arrays should never be put into an STL container or you will suffer
750 // unpredictable results due the way Blitz handles assignment). Nested containers are
751 // considered to be multidimensional arrays. Although gnuplot only supports 1D and 2D arrays,
752 // our module is in principle not limited.
753 //
754 // The ArrayTraits class is specialized for every supported array or container type (the
755 // default, unspecialized, version of ArrayTraits exists only to tell you that something is
756 // *not* a container, via the is_container flag). ArrayTraits tells you the depth of a nested
757 // (or multidimensional) container, as well as the value type, and provides a specialized
758 // sort of iterator (a.k.a. "range"). Ranges are sort of like STL iterators, except that they
759 // have built-in knowledge of the end condition so you don't have to carry around both a
760 // begin() and an end() iterator like in STL.
761 //
762 // As an example of how this works, consider a std::pair of std::vectors. Ultimately this gets
763 // sent to gnuplot as two columns, so the two vectors need to be iterated in lockstep.
764 // The `value_type` of `std::pair<std::vector<T>, std::vector<U>>` is then `std::pair<T, U>`
765 // and this is what deferencing the range (iterator) gives. Internally, this range is built
766 // out of a pair of ranges (PairOfRange class), the `inc()` (advance to next element)
767 // method calls `inc()` on each of the children, and `deref()` calls `deref()` on each child
768 // and combines the results to return a `std::pair`. Tuples are handled as nested pairs.
769 //
770 // In addition to PairOfRange, there is also a VecOfRange class that can be used to treat the
771 // outermost part of a nested container as if it were a tuple. Since tuples are printed as
772 // columns, this is like treating a multidimensional array as if it were column-major. A
773 // VecOfRange is obtained by calling `get_columns_range`. This is used by, for instance,
774 // `send1d_colmajor`. The implementation is similar to that of PairOfRange.
775 //
776 // The range, accessed via `ArrayTraits<T>::get_range`, will be of a different class depending
777 // on T, and this is defined by the ArrayTraits specialization for T. It will always have
778 // methods `inc()` to advance to the next element and `is_end()` for checking whether one has
779 // advanced past the final element. For nested containers, `deref_subiter()` returns a range
780 // iterator for the next nesting level. When at the innermost level of nesting, `deref()`
781 // returns the value of the entry the iterator points to (a scalar, pair, or tuple).
782 // Only one of `deref()` or `deref_subiter()` will be available, depending on whether there are
783 // deeper levels of nesting. The typedefs `value_type` and `subiter_type` tell the return
784 // types of these two methods.
785 //
786 // Support for standard C++ and boost containers and tuples of containers is provided in this
787 // section. Support for third party packages like Blitz and Armadillo is in a later section.
788 
789 // {{{2 ArrayTraits generic class and defaults
790 
791 // Error messages involving this stem from treating something that was not a container as if it
792 // was. This is only here to allow compiliation without errors in normal cases.
794  // This is just here to make VC++ happy.
795  // https://connect.microsoft.com/VisualStudio/feedback/details/777612/class-template-specialization-that-compiles-in-g-but-not-visual-c
796  typedef void subiter_type;
797 };
798 
799 // Error messages involving this stem from calling deref instead of deref_subiter for a nested
800 // container.
802 
803 // The unspecialized version of this class gives traits for things that are *not* arrays.
804 template <typename T, typename Enable=void>
805 class ArrayTraits {
806 public:
807  // The value type of elements after all levels of nested containers have been dereferenced.
809  // The type of the range (a.k.a. iterator) that `get_range()` returns.
811  // Tells whether T is in fact a container type.
812  static const bool is_container = false;
813  // This flag supports the legacy behavior of automatically guessing whether the data should
814  // be treated as column major. This guessing happens when `send()` is called rather than
815  // `send1d()` or `send2d()`. This is deprecated, but is still supported for reverse
816  // compatibility.
817  static const bool allow_auto_unwrap = false;
818  // The number of levels of nesting, or the dimension of multidimensional arrays.
819  static const size_t depth = 0;
820 
821  // Returns the range (iterator) for an array.
822  static range_type get_range(const T &) {
823  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T)==0), "argument was not a container");
824  throw std::logic_error("static assert should have been triggered by this point");
825  }
826 };
827 
828 // Most specializations of ArrayTraits should inherit from this (with V set to the value type).
829 // It sets some default values.
830 template <typename V>
832 public:
833  typedef V value_type;
834 
835  static const bool is_container = true;
836  static const bool allow_auto_unwrap = true;
837  static const size_t depth = ArrayTraits<V>::depth + 1;
838 };
839 
840 // This handles reference types, such as are given with boost::tie.
841 // It also allows for instance "ArrayTraits<T[N]>" to match "ArrayTraits<T (&) [N]>".
842 // I think this is okay to do... The alternative is to use remove_reference all over the place.
843 template <typename T>
844 class ArrayTraits<T&> : public ArrayTraits<T> { };
845 
846 // FIXME - is this okay?
847 // It supports gp.send1d(std::forward_as_tuple(x, std::move(y)));
848 #if GNUPLOT_ENABLE_CXX11
849 template <typename T>
850 class ArrayTraits<T&&> : public ArrayTraits<T> { };
851 #endif
852 
853 // }}}2
854 
855 // {{{2 STL container support
856 
857 template <typename TI, typename TV>
859 public:
861  IteratorRange(const TI &_it, const TI &_end) : it(_it), end(_end) { }
862 
863  static const bool is_container = ArrayTraits<TV>::is_container;
864  typedef typename boost::mpl::if_c<is_container,
867 
868  bool is_end() const { return it == end; }
869 
870  void inc() { ++it; }
871 
872  value_type deref() const {
873  GNUPLOT_STATIC_ASSERT_MSG(sizeof(TV) && !is_container,
874  "deref called on nested container");
875  if(is_end()) {
876  throw std::runtime_error("attepted to dereference past end of iterator");
877  }
878  return *it;
879  }
880 
881  subiter_type deref_subiter() const {
882  GNUPLOT_STATIC_ASSERT_MSG(sizeof(TV) && is_container,
883  "deref_subiter called on non-nested container");
884  if(is_end()) {
885  throw std::runtime_error("attepted to dereference past end of iterator");
886  }
887  return ArrayTraits<TV>::get_range(*it);
888  }
889 
890 private:
891  TI it, end;
892 };
893 
894 template <typename T>
895 class ArrayTraits<T,
896  typename boost::enable_if<is_like_stl_container<T> >::type
897 > : public ArrayTraitsDefaults<typename T::value_type> {
898 public:
900 
901  static range_type get_range(const T &arg) {
902  return range_type(arg.begin(), arg.end());
903  }
904 };
905 
906 // }}}2
907 
908 // {{{2 C style array support
909 
910 template <typename T, size_t N>
911 class ArrayTraits<T[N]> : public ArrayTraitsDefaults<T> {
912 public:
914 
915  static range_type get_range(const T (&arg)[N]) {
916  return range_type(arg, arg+N);
917  }
918 };
919 
920 // }}}2
921 
922 // {{{2 std::pair support
923 
924 template <typename RT, typename RU>
925 class PairOfRange {
926  template <typename T, typename U, typename PrintMode>
927  friend void deref_and_print(std::ostream &, const PairOfRange<T, U> &, PrintMode);
928 
929 public:
931  PairOfRange(const RT &_l, const RU &_r) : l(_l), r(_r) { }
932 
933  static const bool is_container = RT::is_container && RU::is_container;
934 
935  typedef std::pair<typename RT::value_type, typename RU::value_type> value_type;
937 
938  bool is_end() const {
939  bool el = l.is_end();
940  bool er = r.is_end();
941  if(el != er) {
942  throw std::length_error("columns were different lengths");
943  }
944  return el;
945  }
946 
947  void inc() {
948  l.inc();
949  r.inc();
950  }
951 
952  value_type deref() const {
953  return std::make_pair(l.deref(), r.deref());
954  }
955 
956  subiter_type deref_subiter() const {
957  return subiter_type(l.deref_subiter(), r.deref_subiter());
958  }
959 
960 private:
961  RT l;
962  RU r;
963 };
964 
965 template <typename T, typename U>
966 class ArrayTraits<std::pair<T, U> > {
967 public:
969  typedef std::pair<typename ArrayTraits<T>::value_type, typename ArrayTraits<U>::value_type> value_type;
970  static const bool is_container = ArrayTraits<T>::is_container && ArrayTraits<U>::is_container;
971  // Don't allow colwrap since it's already wrapped.
972  static const bool allow_auto_unwrap = false;
973  // It is allowed for l_depth != r_depth, for example one column could be 'double' and the
974  // other column could be 'vector<double>'.
975  static const size_t l_depth = ArrayTraits<T>::depth;
976  static const size_t r_depth = ArrayTraits<U>::depth;
977  static const size_t depth = (l_depth < r_depth) ? l_depth : r_depth;
978 
979  static range_type get_range(const std::pair<T, U> &arg) {
980  return range_type(
981  ArrayTraits<T>::get_range(arg.first),
982  ArrayTraits<U>::get_range(arg.second)
983  );
984  }
985 };
986 
987 // }}}2
988 
989 // {{{2 boost::tuple support
990 
991 template <typename T>
992 class ArrayTraits<T,
993  typename boost::enable_if<
994  boost::mpl::and_<
995  is_boost_tuple<T>,
996  boost::mpl::not_<is_boost_tuple_nulltype<typename T::tail_type> >
997  >
998  >::type
999 > : public ArrayTraits<
1000  typename std::pair<
1001  typename T::head_type,
1002  typename T::tail_type
1003  >
1004 > {
1005 public:
1006  typedef typename T::head_type HT;
1007  typedef typename T::tail_type TT;
1008 
1010 
1011  static typename parent::range_type get_range(const T &arg) {
1012  return typename parent::range_type(
1013  ArrayTraits<HT>::get_range(arg.get_head()),
1014  ArrayTraits<TT>::get_range(arg.get_tail())
1015  );
1016  }
1017 };
1018 
1019 template <typename T>
1020 class ArrayTraits<T,
1021  typename boost::enable_if<
1022  boost::mpl::and_<
1023  is_boost_tuple<T>,
1024  is_boost_tuple_nulltype<typename T::tail_type>
1025  >
1026  >::type
1027 > : public ArrayTraits<
1028  typename T::head_type
1029 > {
1030  typedef typename T::head_type HT;
1031 
1033 
1034 public:
1035  static typename parent::range_type get_range(const T &arg) {
1036  return parent::get_range(arg.get_head());
1037  }
1038 };
1039 
1040 // }}}2
1041 
1042 // {{{2 std::tuple support
1043 
1044 #if GNUPLOT_ENABLE_CXX11
1045 
1046 template <typename Tuple, size_t idx>
1047 struct StdTupUnwinder {
1048  typedef std::pair<
1049  typename StdTupUnwinder<Tuple, idx-1>::type,
1050  typename std::tuple_element<idx, Tuple>::type
1051  > type;
1052 
1053  static typename ArrayTraits<type>::range_type get_range(const Tuple &arg) {
1054  return typename ArrayTraits<type>::range_type(
1055  StdTupUnwinder<Tuple, idx-1>::get_range(arg),
1056  ArrayTraits<typename std::tuple_element<idx, Tuple>::type>::get_range(std::get<idx>(arg))
1057  );
1058  }
1059 };
1060 
1061 template <typename Tuple>
1062 struct StdTupUnwinder<Tuple, 0> {
1063  typedef typename std::tuple_element<0, Tuple>::type type;
1064 
1065  static typename ArrayTraits<type>::range_type get_range(const Tuple &arg) {
1066  return ArrayTraits<type>::get_range(std::get<0>(arg));
1067  }
1068 };
1069 
1070 template <typename... Args>
1071 class ArrayTraits<std::tuple<Args...> > :
1072  public ArrayTraits<typename StdTupUnwinder<std::tuple<Args...>, sizeof...(Args)-1>::type>
1073 {
1074  typedef std::tuple<Args...> Tuple;
1075  typedef ArrayTraits<typename StdTupUnwinder<Tuple, sizeof...(Args)-1>::type> parent;
1076 
1077 public:
1078  static typename parent::range_type get_range(const Tuple &arg) {
1079  return StdTupUnwinder<std::tuple<Args...>, sizeof...(Args)-1>::get_range(arg);
1080  }
1081 };
1082 
1083 #endif // GNUPLOT_ENABLE_CXX11
1084 
1085 // }}}2
1086 
1087 // {{{2 Support column unwrap of container (VecOfRange)
1088 //
1089 // VecOfRange (created via `get_columns_range()`) treats the outermost level of a nested
1090 // container as if it were a tuple. Since tuples are sent to gnuplot as columns, this has the
1091 // effect of addressing a multidimensional array in column major order.
1092 
1093 template <typename RT>
1094 class VecOfRange {
1095  template <typename T, typename PrintMode>
1096  friend void deref_and_print(std::ostream &, const VecOfRange<T> &, PrintMode);
1097 
1098 public:
1100  explicit VecOfRange(const std::vector<RT> &_rvec) : rvec(_rvec) { }
1101 
1102  static const bool is_container = RT::is_container;
1103  // Don't allow colwrap since it's already wrapped.
1104  static const bool allow_auto_unwrap = false;
1105 
1106  typedef std::vector<typename RT::value_type> value_type;
1108 
1109  bool is_end() const {
1110  if(rvec.empty()) return true;
1111  bool ret = rvec[0].is_end();
1112  for(size_t i=1; i<rvec.size(); i++) {
1113  if(ret != rvec[i].is_end()) {
1114  throw std::length_error("columns were different lengths");
1115  }
1116  }
1117  return ret;
1118  }
1119 
1120  void inc() {
1121  for(size_t i=0; i<rvec.size(); i++) {
1122  rvec[i].inc();
1123  }
1124  }
1125 
1126  value_type deref() const {
1127  value_type ret(rvec.size());
1128  for(size_t i=0; i<rvec.size(); i++) {
1129  ret[i] = rvec[i].deref();
1130  }
1131  return ret;
1132  }
1133 
1134  subiter_type deref_subiter() const {
1135  std::vector<typename RT::subiter_type> subvec(rvec.size());
1136  for(size_t i=0; i<rvec.size(); i++) {
1137  subvec[i] = rvec[i].deref_subiter();
1138  }
1139  return subiter_type(subvec);
1140  }
1141 
1142 private:
1143  std::vector<RT> rvec;
1144 };
1145 
1146 template <typename T>
1148 get_columns_range(const T &arg) {
1149  typedef typename ArrayTraits<T>::range_type::subiter_type U;
1150  std::vector<U> rvec;
1152  while(!outer.is_end()) {
1153  rvec.push_back(outer.deref_subiter());
1154  outer.inc();
1155  }
1156  VecOfRange<U> ret(rvec);
1157  return ret;
1158 }
1159 
1160 // }}}2
1161 
1162 // }}}1
1163 
1164 // {{{1 Array printing functions
1165 //
1166 // This section coordinates the sending of data to gnuplot. The ArrayTraits mechanism tells us
1167 // about nested containers and provides iterators over them. Here we make use of this,
1168 // deciding what dimensions should be treated as rows, columns, or blocks, telling gnuplot the
1169 // size of the array if needed, and so on.
1170 
1171 // If this is set, then text-mode data will be sent in a format that is not compatible with
1172 // gnuplot, but which helps the programmer tell what the library is thinking. Basically it
1173 // puts brackets around groups of items and puts a message delineating blocks of data.
1174 static bool debug_array_print = 0;
1175 
1176 // This is thrown when an empty container is being plotted. This exception should always
1177 // be caught and should not propagate to the user.
1178 class plotting_empty_container : public std::length_error {
1179 public:
1180  plotting_empty_container() : std::length_error("plotting empty container") { }
1181 };
1182 
1183 // {{{2 Tags (like enums for metaprogramming)
1184 
1185 // These tags define what our goal is, what sort of thing should ultimately be sent to the
1186 // ostream. These tags are passed to the PrintMode template argument of the functions in this
1187 // section.
1188 //
1189 // ModeText - Sends the data in an array in text format
1190 // ModeBinary - Sends the data in an array in binary format
1191 // ModeBinfmt - Sends the gnuplot format code for binary data (e.g. "%double%double")
1192 // ModeSize - Sends the size of an array. Needed when sending binary data.
1193 struct ModeText { static const bool is_text = 1; static const bool is_binfmt = 0; static const bool is_size = 0; };
1194 struct ModeBinary { static const bool is_text = 0; static const bool is_binfmt = 0; static const bool is_size = 0; };
1195 struct ModeBinfmt { static const bool is_text = 0; static const bool is_binfmt = 1; static const bool is_size = 0; };
1196 struct ModeSize { static const bool is_text = 0; static const bool is_binfmt = 0; static const bool is_size = 1; };
1197 
1198 // Whether to treat the outermost level of a nested container as columns (column major mode).
1199 struct ColUnwrapNo { };
1200 struct ColUnwrapYes { };
1201 
1202 // The user must give a hint to describe how nested containers are to be interpreted. This is
1203 // done by calling e.g. `send1d_colmajor()` or `send2d()`. This hint is then described by the
1204 // following tags. This is passed to the OrganizationMode template argument.
1205 struct Mode1D { static std::string class_name() { return "Mode1D" ; } };
1206 struct Mode2D { static std::string class_name() { return "Mode2D" ; } };
1207 struct Mode1DUnwrap { static std::string class_name() { return "Mode1DUnwrap"; } };
1208 struct Mode2DUnwrap { static std::string class_name() { return "Mode2DUnwrap"; } };
1209 // Support for the legacy behavior that guesses which of the above four modes should be used.
1210 struct ModeAuto { static std::string class_name() { return "ModeAuto" ; } };
1211 
1212 // }}}2
1213 
1214 // {{{2 ModeAutoDecoder
1215 //
1216 // ModeAuto guesses which of Mode1D, Mode2D, Mode1DUnwrap, or Mode2DUnwrap should be used.
1217 // This is provided for reverse compatibility; it is better to specify explicitly which mode to
1218 // use. Since this is only for reverse compatibility, and shouldn't be used, I'm not going to
1219 // spell out what the rules are. See below for details.
1220 
1221 template <typename T, typename Enable=void>
1222 struct ModeAutoDecoder { };
1223 
1224 template <typename T>
1226  typename boost::enable_if_c<
1227  (ArrayTraits<T>::depth == 1)
1228  >::type>
1229 {
1230  typedef Mode1D mode;
1231 };
1232 
1233 template <typename T>
1235  typename boost::enable_if_c<
1236  (ArrayTraits<T>::depth == 2) &&
1237  !ArrayTraits<T>::allow_auto_unwrap
1238  >::type>
1239 {
1240  typedef Mode2D mode;
1241 };
1242 
1243 template <typename T>
1245  typename boost::enable_if_c<
1246  (ArrayTraits<T>::depth == 2) &&
1247  ArrayTraits<T>::allow_auto_unwrap
1248  >::type>
1249 {
1251 };
1252 
1253 template <typename T>
1254 struct ModeAutoDecoder<T,
1255  typename boost::enable_if_c<
1256  (ArrayTraits<T>::depth > 2) &&
1257  ArrayTraits<T>::allow_auto_unwrap
1258  >::type>
1259 {
1260  typedef Mode2DUnwrap mode;
1261 };
1262 
1263 template <typename T>
1264 struct ModeAutoDecoder<T,
1265  typename boost::enable_if_c<
1266  (ArrayTraits<T>::depth > 2) &&
1267  !ArrayTraits<T>::allow_auto_unwrap
1268  >::type>
1269 {
1270  typedef Mode2D mode;
1271 };
1272 
1273 // }}}2
1274 
1275 // The data is processed using several levels of functions that call each other in sequence,
1276 // each defined in a subsection of code below. Because C++ wants you to declare a function
1277 // before using it, we begin with the innermost function. So in order to see the sequence in
1278 // which these are called, you should read the following subsections in reverse order. Nested
1279 // arrays are formated into blocks (for 2D data) and lines (for 1D or 2D data), then further
1280 // nesting levels are formatted into columns. Also tag dispatching is used in order to define
1281 // various sorts of behavior. Each of these tasks is handled by one of the following
1282 // subsections.
1283 
1284 // {{{2 send_scalar()
1285 //
1286 // Send a scalar in one of three possible ways: via TextSender, BinarySender, or BinfmtSender,
1287 // depending on which PrintMode tag is passed to the function.
1288 
1289 template <typename T>
1290 void send_scalar(std::ostream &stream, const T &arg, ModeText) {
1291  TextSender<T>::send(stream, arg);
1292 }
1293 
1294 template <typename T>
1295 void send_scalar(std::ostream &stream, const T &arg, ModeBinary) {
1296  BinarySender<T>::send(stream, arg);
1297 }
1298 
1299 template <typename T>
1300 void send_scalar(std::ostream &stream, const T &, ModeBinfmt) {
1301  BinfmtSender<T>::send(stream);
1302 }
1303 
1304 // }}}2
1305 
1306 // {{{2 deref_and_print()
1307 //
1308 // Dereferences and prints the given range (iterator). At this point we are done with treating
1309 // containers as blocks (for 2D data) and lines (for 1D or 2D data). Any further levels of
1310 // nested containers will at this point be treated as columns.
1311 
1312 // If arg is not a container, then print it via send_scalar().
1313 template <typename T, typename PrintMode>
1314 typename boost::disable_if_c<T::is_container>::type
1315 deref_and_print(std::ostream &stream, const T &arg, PrintMode) {
1316  const typename T::value_type &v = arg.deref();
1317  send_scalar(stream, v, PrintMode());
1318 }
1319 
1320 // If arg is a container (but not a PairOfRange or VecOfRange, which are handled below) then
1321 // treat the contents as columns, iterating over the contents recursively. If outputting in
1322 // text mode, put a space between columns.
1323 template <typename T, typename PrintMode>
1324 typename boost::enable_if_c<T::is_container>::type
1325 deref_and_print(std::ostream &stream, const T &arg, PrintMode) {
1326  if(arg.is_end()) throw plotting_empty_container();
1327  typename T::subiter_type subrange = arg.deref_subiter();
1328  if(PrintMode::is_binfmt && subrange.is_end()) throw plotting_empty_container();
1329  if(debug_array_print && PrintMode::is_text) stream << "{";
1330  bool first = true;
1331  while(!subrange.is_end()) {
1332  if(!first && PrintMode::is_text) stream << " ";
1333  first = false;
1334  deref_and_print(stream, subrange, PrintMode());
1335  subrange.inc();
1336  }
1337  if(debug_array_print && PrintMode::is_text) stream << "}";
1338 }
1339 
1340 // PairOfRange is treated as columns. In text mode, put a space between columns.
1341 template <typename T, typename U, typename PrintMode>
1342 void deref_and_print(std::ostream &stream, const PairOfRange<T, U> &arg, PrintMode) {
1343  deref_and_print(stream, arg.l, PrintMode());
1344  if(PrintMode::is_text) stream << " ";
1345  deref_and_print(stream, arg.r, PrintMode());
1346 }
1347 
1348 // VecOfRange is treated as columns. In text mode, put a space between columns.
1349 template <typename T, typename PrintMode>
1350 void deref_and_print(std::ostream &stream, const VecOfRange<T> &arg, PrintMode) {
1351  if(PrintMode::is_binfmt && arg.rvec.empty()) throw plotting_empty_container();
1352  for(size_t i=0; i<arg.rvec.size(); i++) {
1353  if(i && PrintMode::is_text) stream << " ";
1354  deref_and_print(stream, arg.rvec[i], PrintMode());
1355  }
1356 }
1357 
1358 // }}}2
1359 
1360 // {{{2 print_block()
1361 //
1362 // Here we format nested containers into blocks (for 2D data) and lines. Actually, block and
1363 // line formatting is only truely needed for text mode output, but for uniformity this function
1364 // is also invoked in binary mode (the PrintMode tag determines the output mode). If the goal
1365 // is to just print the array size or the binary format string, then the loops exit after the
1366 // first iteration.
1367 //
1368 // The Depth argument tells how deep to recurse. It will be either `2` for 2D data, formatted
1369 // into blocks and lines, with empty lines between blocks, or `1` for 1D data formatted into
1370 // lines but not blocks. Gnuplot only supports 1D and 2D data, but if it were to support 3D in
1371 // the future (e.g. volume rendering), all that would be needed would be some trivial changes
1372 // in this section. After Depth number of nested containers have been recursed into, control
1373 // is passed to deref_and_print(), which treats any further nested containers as columns.
1374 
1375 // Depth==1 and we are not asked to print the size of the array. Send each element of the
1376 // range to deref_and_print() for further processing into columns.
1377 template <size_t Depth, typename T, typename PrintMode>
1378 typename boost::enable_if_c<(Depth==1) && !PrintMode::is_size>::type
1379 print_block(std::ostream &stream, T &arg, PrintMode) {
1380  if(PrintMode::is_binfmt && arg.is_end()) throw plotting_empty_container();
1381  for(; !arg.is_end(); arg.inc()) {
1382  //print_entry(arg.deref());
1383  deref_and_print(stream, arg, PrintMode());
1384  // If asked to print the binary format string, only the first element needs to be
1385  // looked at.
1386  if(PrintMode::is_binfmt) break;
1387  if(PrintMode::is_text) stream << std::endl;
1388  }
1389 }
1390 
1391 // Depth>1 and we are not asked to print the size of the array. Loop over the range and
1392 // recurse into print_block() with Depth -> Depth-1.
1393 template <size_t Depth, typename T, typename PrintMode>
1394 typename boost::enable_if_c<(Depth>1) && !PrintMode::is_size>::type
1395 print_block(std::ostream &stream, T &arg, PrintMode) {
1396  if(PrintMode::is_binfmt && arg.is_end()) throw plotting_empty_container();
1397  bool first = true;
1398  for(; !arg.is_end(); arg.inc()) {
1399  if(first) {
1400  first = false;
1401  } else {
1402  if(PrintMode::is_text) stream << std::endl;
1403  }
1404  if(debug_array_print && PrintMode::is_text) stream << "<block>" << std::endl;
1405  if(arg.is_end()) throw plotting_empty_container();
1406  typename T::subiter_type sub = arg.deref_subiter();
1407  print_block<Depth-1>(stream, sub, PrintMode());
1408  // If asked to print the binary format string, only the first element needs to be
1409  // looked at.
1410  if(PrintMode::is_binfmt) break;
1411  }
1412 }
1413 
1414 // Determine how many elements are in the given range. Used in the functions below.
1415 template <typename T>
1416 size_t get_range_size(const T &arg) {
1417  // FIXME - not the fastest way. Implement a size() method for range.
1418  size_t ret = 0;
1419  for(T i=arg; !i.is_end(); i.inc()) ++ret;
1420  return ret;
1421 }
1422 
1423 // Depth==1 and we are asked to print the size of the array.
1424 template <size_t Depth, typename T, typename PrintMode>
1425 typename boost::enable_if_c<(Depth==1) && PrintMode::is_size>::type
1426 print_block(std::ostream &stream, T &arg, PrintMode) {
1427  stream << get_range_size(arg);
1428 }
1429 
1430 // Depth>1 and we are asked to print the size of the array.
1431 template <size_t Depth, typename T, typename PrintMode>
1432 typename boost::enable_if_c<(Depth>1) && PrintMode::is_size>::type
1433 print_block(std::ostream &stream, T &arg, PrintMode) {
1434  if(arg.is_end()) throw plotting_empty_container();
1435  // It seems that size for two dimensional arrays needs the fastest varying index first,
1436  // contrary to intuition. The gnuplot documentation is not too clear on this point.
1437  typename T::subiter_type sub = arg.deref_subiter();
1438  print_block<Depth-1>(stream, sub, PrintMode());
1439  stream << "," << get_range_size(arg);
1440 }
1441 
1442 // }}}2
1443 
1444 // {{{2 handle_colunwrap_tag()
1445 //
1446 // If passed the ColUnwrapYes then treat the outermost nested container as columns by calling
1447 // get_columns_range(). Otherwise just call get_range(). The range iterator is then passed to
1448 // print_block() for further processing.
1449 
1450 template <size_t Depth, typename T, typename PrintMode>
1451 void handle_colunwrap_tag(std::ostream &stream, const T &arg, ColUnwrapNo, PrintMode) {
1452  GNUPLOT_STATIC_ASSERT_MSG(ArrayTraits<T>::depth >= Depth, "container not deep enough");
1454  print_block<Depth>(stream, range, PrintMode());
1455 }
1456 
1457 template <size_t Depth, typename T, typename PrintMode>
1458 void handle_colunwrap_tag(std::ostream &stream, const T &arg, ColUnwrapYes, PrintMode) {
1459  GNUPLOT_STATIC_ASSERT_MSG(ArrayTraits<T>::depth >= Depth+1, "container not deep enough");
1461  print_block<Depth>(stream, cols, PrintMode());
1462 }
1463 
1464 // }}}2
1465 
1466 // {{{2 handle_organization_tag()
1467 //
1468 // Parse the OrganizationMode tag then forward to handle_colunwrap_tag() for further
1469 // processing. If passed the Mode1D or Mode2D tags, then set Depth=1 or Depth=2. If passed
1470 // Mode{1,2}DUnwrap then use the ColUnwrapYes tag. If passed ModeAuto (which is for legacy
1471 // support) then use ModeAutoDecoder to guess which of Mode1D, Mode2D, etc. should be used.
1472 
1473 template <typename T, typename PrintMode>
1474 void handle_organization_tag(std::ostream &stream, const T &arg, Mode1D, PrintMode) {
1475  handle_colunwrap_tag<1>(stream, arg, ColUnwrapNo(), PrintMode());
1476 }
1477 
1478 template <typename T, typename PrintMode>
1479 void handle_organization_tag(std::ostream &stream, const T &arg, Mode2D, PrintMode) {
1480  handle_colunwrap_tag<2>(stream, arg, ColUnwrapNo(), PrintMode());
1481 }
1482 
1483 template <typename T, typename PrintMode>
1484 void handle_organization_tag(std::ostream &stream, const T &arg, Mode1DUnwrap, PrintMode) {
1485  handle_colunwrap_tag<1>(stream, arg, ColUnwrapYes(), PrintMode());
1486 }
1487 
1488 template <typename T, typename PrintMode>
1489 void handle_organization_tag(std::ostream &stream, const T &arg, Mode2DUnwrap, PrintMode) {
1490  handle_colunwrap_tag<2>(stream, arg, ColUnwrapYes(), PrintMode());
1491 }
1492 
1493 template <typename T, typename PrintMode>
1494 void handle_organization_tag(std::ostream &stream, const T &arg, ModeAuto, PrintMode) {
1495  handle_organization_tag(stream, arg, typename ModeAutoDecoder<T>::mode(), PrintMode());
1496 }
1497 
1498 // }}}2
1499 
1500 // The entry point for the processing defined in this section. It just forwards immediately to
1501 // handle_organization_tag(). This function is only here to give a sane name to the entry
1502 // point.
1503 //
1504 // The allowed values for the OrganizationMode and PrintMode tags are defined in the beginning
1505 // of this section.
1506 template <typename T, typename OrganizationMode, typename PrintMode>
1507 void top_level_array_sender(std::ostream &stream, const T &arg, OrganizationMode, PrintMode) {
1508  handle_organization_tag(stream, arg, OrganizationMode(), PrintMode());
1509 }
1510 
1511 // }}}1
1512 
1513 // {{{1 FileHandleWrapper
1514 
1515 // This holds the file handle that gnuplot commands will be sent to. The purpose of this
1516 // wrapper is twofold:
1517 // 1. It allows storing the FILE* before it gets passed to the boost::iostreams::stream
1518 // constructor (which is a base class of the main Gnuplot class). This is accomplished
1519 // via multiple inheritance as described at http://stackoverflow.com/a/3821756/1048959
1520 // 2. It remembers whether the handle needs to be closed via fclose or pclose.
1522  FileHandleWrapper(std::FILE *_fh, bool _should_use_pclose) :
1523  wrapped_fh(_fh), should_use_pclose(_should_use_pclose) { }
1524 
1525  void fh_close() {
1526  if(should_use_pclose) {
1527  if(GNUPLOT_PCLOSE(wrapped_fh)) {
1528  std::cerr << "pclose returned error" << std::endl;
1529  }
1530  } else {
1531  if(fclose(wrapped_fh)) {
1532  std::cerr << "fclose returned error" << std::endl;
1533  }
1534  }
1535  }
1536 
1537  int fh_fileno() {
1538  return GNUPLOT_FILENO(wrapped_fh);
1539  }
1540 
1541  std::FILE *wrapped_fh;
1543 };
1544 
1545 // }}}1
1546 
1547 // {{{1 Main class
1548 
1549 class Gnuplot :
1550  // Some setup needs to be done before obtaining the file descriptor that gets passed to
1551  // boost::iostreams::stream. This is accomplished by using a multiple inheritance trick,
1552  // as described at http://stackoverflow.com/a/3821756/1048959
1553  private FileHandleWrapper,
1554  public boost::iostreams::stream<boost::iostreams::file_descriptor_sink>
1555 {
1556 private:
1557  static std::string get_default_cmd() {
1559  char *from_env = std::getenv("GNUPLOT_IOSTREAM_CMD");
1561  if(from_env && from_env[0]) {
1562  return from_env;
1563  } else {
1564  return GNUPLOT_DEFAULT_COMMAND;
1565  }
1566  }
1567 
1568  static FileHandleWrapper open_cmdline(const std::string &in) {
1569  std::string cmd = in.empty() ? get_default_cmd() : in;
1570  assert(!cmd.empty());
1571  if(cmd[0] == '>') {
1572  std::string fn = cmd.substr(1);
1574  FILE *fh = std::fopen(fn.c_str(), "w");
1576  if(!fh) throw(std::ios_base::failure("cannot open file "+fn));
1577  return FileHandleWrapper(fh, false);
1578  } else {
1579  FILE *fh = GNUPLOT_POPEN(cmd.c_str(), "w");
1580  if(!fh) throw(std::ios_base::failure("cannot open pipe "+cmd));
1581  return FileHandleWrapper(fh, true);
1582  }
1583  }
1584 
1585 public:
1586  explicit Gnuplot(const std::string &_cmd="") :
1587  FileHandleWrapper(open_cmdline(_cmd)),
1588  boost::iostreams::stream<boost::iostreams::file_descriptor_sink>(
1589  fh_fileno(),
1590 #if BOOST_VERSION >= 104400
1591  boost::iostreams::never_close_handle
1592 #else
1593  false
1594 #endif
1595  ),
1596  feedback(NULL),
1597  tmp_files(),
1598  debug_messages(false)
1599  {
1600  *this << std::scientific << std::setprecision(18); // refer <iomanip>
1601  }
1602 
1603  explicit Gnuplot(FILE *_fh) :
1604  FileHandleWrapper(_fh, 0),
1605  boost::iostreams::stream<boost::iostreams::file_descriptor_sink>(
1606  fh_fileno(),
1607 #if BOOST_VERSION >= 104400
1608  boost::iostreams::never_close_handle
1609 #else
1610  false
1611 #endif
1612  ),
1613  feedback(NULL),
1614  tmp_files(),
1615  debug_messages(false)
1616  {
1617  *this << std::scientific << std::setprecision(18); // refer <iomanip>
1618  }
1619 
1620 private:
1621  // noncopyable
1622  Gnuplot(const Gnuplot &);
1623  const Gnuplot& operator=(const Gnuplot &);
1624 
1625 public:
1627  if(debug_messages) {
1628  std::cerr << "ending gnuplot session" << std::endl;
1629  }
1630 
1631  // FIXME - boost's close method calls close() on the file descriptor, but we need to
1632  // use sometimes use pclose instead. For now, just skip calling boost's close and use
1633  // flush just in case.
1634  do_flush();
1635  // Wish boost had a pclose method...
1636  //close();
1637 
1638  fh_close();
1639 
1640  delete feedback;
1641  }
1642 
1643  void clearTmpfiles() {
1644  // destructors will cause deletion
1645  tmp_files.clear();
1646  }
1647 
1648 private:
1649  void do_flush() {
1650  *this << std::flush;
1651  fflush(wrapped_fh);
1652  }
1653 
1654  std::string make_tmpfile() {
1655 #ifdef GNUPLOT_USE_TMPFILE
1656  boost::shared_ptr<GnuplotTmpfile> tmp_file(new GnuplotTmpfile());
1657  // The file will be removed once the pointer is removed from the
1658  // tmp_files container.
1659  tmp_files.push_back(tmp_file);
1660  return tmp_file->file.string();
1661 #else
1662  throw(std::logic_error("no filename given and temporary files not enabled"));
1663 #endif // GNUPLOT_USE_TMPFILE
1664  }
1665 
1666 public:
1667 // {{{2 Generic sender routines.
1668 //
1669 // These are declared public, but are undocumented. It is recommended to use the functions in
1670 // the next section, which serve as adapters that pass specific values for the OrganizationMode
1671 // tag.
1672 
1673  template <typename T, typename OrganizationMode>
1674  Gnuplot &send(const T &arg, OrganizationMode) {
1675  top_level_array_sender(*this, arg, OrganizationMode(), ModeText());
1676  *this << "e" << std::endl; // gnuplot's "end of array" token
1677  do_flush(); // probably not really needed, but doesn't hurt
1678  return *this;
1679  }
1680 
1681  template <typename T, typename OrganizationMode>
1682  Gnuplot &sendBinary(const T &arg, OrganizationMode) {
1683  top_level_array_sender(*this, arg, OrganizationMode(), ModeBinary());
1684  do_flush(); // probably not really needed, but doesn't hurt
1685  return *this;
1686  }
1687 
1688  template <typename T, typename OrganizationMode>
1689  std::string binfmt(const T &arg, const std::string &arr_or_rec, OrganizationMode) {
1690  assert((arr_or_rec == "array") || (arr_or_rec == "record"));
1691  std::string ret;
1692  try {
1693  std::ostringstream tmp;
1694  tmp << " format='";
1695  top_level_array_sender(tmp, arg, OrganizationMode(), ModeBinfmt());
1696  tmp << "' " << arr_or_rec << "=(";
1697  top_level_array_sender(tmp, arg, OrganizationMode(), ModeSize());
1698  tmp << ")";
1699  tmp << " ";
1700  ret = tmp.str();
1701  } catch(const plotting_empty_container &) {
1702  ret = std::string(" format='' ") + arr_or_rec + "=(0) ";
1703  }
1704  return ret;
1705  }
1706 
1707  // NOTE: empty filename makes temporary file
1708  template <typename T, typename OrganizationMode>
1709  std::string file(const T &arg, std::string filename, OrganizationMode) {
1710  if(filename.empty()) filename = make_tmpfile();
1711  std::fstream tmp_stream(filename.c_str(), std::fstream::out);
1712  top_level_array_sender(tmp_stream, arg, OrganizationMode(), ModeText());
1713  tmp_stream.close();
1714 
1715  std::ostringstream cmdline;
1716  // FIXME - hopefully filename doesn't contain quotes or such...
1717  cmdline << " '" << filename << "' ";
1718  return cmdline.str();
1719  }
1720 
1721  // NOTE: empty filename makes temporary file
1722  template <typename T, typename OrganizationMode>
1723  std::string binaryFile(const T &arg, std::string filename, const std::string &arr_or_rec, OrganizationMode) {
1724  if(filename.empty()) filename = make_tmpfile();
1725  std::fstream tmp_stream(filename.c_str(), std::fstream::out | std::fstream::binary);
1726  top_level_array_sender(tmp_stream, arg, OrganizationMode(), ModeBinary());
1727  tmp_stream.close();
1728 
1729  std::ostringstream cmdline;
1730  // FIXME - hopefully filename doesn't contain quotes or such...
1731  cmdline << " '" << filename << "' binary" << binfmt(arg, arr_or_rec, OrganizationMode());
1732  return cmdline.str();
1733  }
1734 
1735 // }}}2
1736 
1737 // {{{2 Deprecated data sending interface that guesses an appropriate OrganizationMode. This is here
1738 // for reverse compatibility. Don't use it. A warning will be printed if
1739 // GNUPLOT_DEPRECATE_WARN is defined.
1740 
1741  template <typename T> Gnuplot GNUPLOT_DEPRECATE("use send1d or send2d")
1742  &send(const T &arg) { return send(arg, ModeAuto()); }
1743 
1744  template <typename T> std::string GNUPLOT_DEPRECATE("use binfmt1d or binfmt2d")
1745  binfmt(const T &arg, const std::string &arr_or_rec="array")
1746  { return binfmt(arg, arr_or_rec, ModeAuto()); }
1747 
1748  template <typename T> Gnuplot GNUPLOT_DEPRECATE("use sendBinary1d or sendBinary2d")
1749  &sendBinary(const T &arg) { return sendBinary(arg, ModeAuto()); }
1750 
1751  template <typename T> std::string GNUPLOT_DEPRECATE("use file1d or file2d")
1752  file(const T &arg, const std::string &filename="")
1753  { return file(arg, filename, ModeAuto()); }
1754 
1755  template <typename T> std::string GNUPLOT_DEPRECATE("use binArr1d or binArr2d")
1756  binaryFile(const T &arg, const std::string &filename="", const std::string &arr_or_rec="array")
1757  { return binaryFile(arg, filename, arr_or_rec, ModeAuto()); }
1758 
1759 // }}}2
1760 
1761 // {{{2 Public (documented) data sending interface.
1762 //
1763 // It seems odd to define 16 different functions, but I think this ends up being the most
1764 // convenient in terms of usage by the end user.
1765 
1766  template <typename T> Gnuplot &send1d (const T &arg) { return send(arg, Mode1D ()); }
1767  template <typename T> Gnuplot &send2d (const T &arg) { return send(arg, Mode2D ()); }
1768  template <typename T> Gnuplot &send1d_colmajor(const T &arg) { return send(arg, Mode1DUnwrap()); }
1769  template <typename T> Gnuplot &send2d_colmajor(const T &arg) { return send(arg, Mode2DUnwrap()); }
1770 
1771  template <typename T> Gnuplot &sendBinary1d (const T &arg) { return sendBinary(arg, Mode1D ()); }
1772  template <typename T> Gnuplot &sendBinary2d (const T &arg) { return sendBinary(arg, Mode2D ()); }
1773  template <typename T> Gnuplot &sendBinary1d_colmajor(const T &arg) { return sendBinary(arg, Mode1DUnwrap()); }
1774  template <typename T> Gnuplot &sendBinary2d_colmajor(const T &arg) { return sendBinary(arg, Mode2DUnwrap()); }
1775 
1776  template <typename T> std::string file1d (const T &arg, const std::string &filename="") { return file(arg, filename, Mode1D ()); }
1777  template <typename T> std::string file2d (const T &arg, const std::string &filename="") { return file(arg, filename, Mode2D ()); }
1778  template <typename T> std::string file1d_colmajor(const T &arg, const std::string &filename="") { return file(arg, filename, Mode1DUnwrap()); }
1779  template <typename T> std::string file2d_colmajor(const T &arg, const std::string &filename="") { return file(arg, filename, Mode2DUnwrap()); }
1780 
1781  template <typename T> std::string binFmt1d (const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode1D ()); }
1782  template <typename T> std::string binFmt2d (const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode2D ()); }
1783  template <typename T> std::string binFmt1d_colmajor(const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode1DUnwrap()); }
1784  template <typename T> std::string binFmt2d_colmajor(const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode2DUnwrap()); }
1785 
1786  template <typename T> std::string binFile1d (const T &arg, const std::string &arr_or_rec, const std::string &filename="") { return binaryFile(arg, filename, arr_or_rec, Mode1D ()); }
1787  template <typename T> std::string binFile2d (const T &arg, const std::string &arr_or_rec, const std::string &filename="") { return binaryFile(arg, filename, arr_or_rec, Mode2D ()); }
1788  template <typename T> std::string binFile1d_colmajor(const T &arg, const std::string &arr_or_rec, const std::string &filename="") { return binaryFile(arg, filename, arr_or_rec, Mode1DUnwrap()); }
1789  template <typename T> std::string binFile2d_colmajor(const T &arg, const std::string &arr_or_rec, const std::string &filename="") { return binaryFile(arg, filename, arr_or_rec, Mode2DUnwrap()); }
1790 
1791 // }}}2
1792 
1793 #ifdef GNUPLOT_ENABLE_FEEDBACK
1794 public:
1795  // Input variables are set to the mouse position and button. If the gnuplot
1796  // window is closed, button -1 is returned. The msg parameter is the prompt
1797  // that is printed to the console.
1798  void getMouse(
1799  double &mx, double &my, int &mb,
1800  std::string msg="Click Mouse!"
1801  ) {
1802  allocFeedback();
1803 
1804  *this << "set mouse" << std::endl;
1805  *this << "pause mouse \"" << msg << "\\n\"" << std::endl;
1806  *this << "if (exists(\"MOUSE_X\")) print MOUSE_X, MOUSE_Y, MOUSE_BUTTON; else print 0, 0, -1;" << std::endl;
1807  if(debug_messages) {
1808  std::cerr << "begin scanf" << std::endl;
1809  }
1810  if(3 != fscanf(feedback->handle(), "%50lf %50lf %50d", &mx, &my, &mb)) {
1811  throw std::runtime_error("could not parse reply");
1812  }
1813  if(debug_messages) {
1814  std::cerr << "end scanf" << std::endl;
1815  }
1816  }
1817 
1818 private:
1819  void allocFeedback() {
1820  if(!feedback) {
1821 #ifdef GNUPLOT_ENABLE_PTY
1822  feedback = new GnuplotFeedbackPty(debug_messages);
1823 //#elif defined GNUPLOT_USE_TMPFILE
1825 // feedback = new GnuplotFeedbackTmpfile(debug_messages);
1826 #else
1827  // This shouldn't happen because we are in an `#ifdef GNUPLOT_ENABLE_FEEDBACK`
1828  // block which should only be activated if GNUPLOT_ENABLE_PTY is defined.
1829  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "No feedback mechanism defined.");
1830 #endif
1831  *this << "set print \"" << feedback->filename() << "\"" << std::endl;
1832  }
1833  }
1834 #endif // GNUPLOT_ENABLE_FEEDBACK
1835 
1836 private:
1837  GnuplotFeedback *feedback;
1838 #ifdef GNUPLOT_USE_TMPFILE
1839  std::vector<boost::shared_ptr<GnuplotTmpfile> > tmp_files;
1840 #else
1841  // just a placeholder
1842  std::vector<int> tmp_files;
1843 #endif // GNUPLOT_USE_TMPFILE
1844 
1845 public:
1847 };
1848 
1849 // }}}1
1850 
1851 } // namespace gnuplotio
1852 
1853 // The first version of this library didn't use namespaces, and now this must be here forever
1854 // for reverse compatibility.
1855 using gnuplotio::Gnuplot;
1856 
1857 #endif // GNUPLOT_IOSTREAM_H
1858 
1859 // {{{1 Support for 3rd party array libraries
1860 
1861 // {{{2 Blitz support
1862 
1863 // This is outside of the main header guard so that it will be compiled when people do
1864 // something like this:
1865 // #include "gnuplot-iostream.h"
1866 // #include <blitz/array.h>
1867 // #include "gnuplot-iostream.h"
1868 // Note that it has its own header guard to avoid double inclusion.
1869 
1870 #ifdef BZ_BLITZ_H
1871 #ifndef GNUPLOT_BLITZ_SUPPORT_LOADED
1872 #define GNUPLOT_BLITZ_SUPPORT_LOADED
1873 namespace gnuplotio {
1874 
1875 template <typename T, int N>
1876 struct BinfmtSender<blitz::TinyVector<T, N> > {
1877  static void send(std::ostream &stream) {
1878  for(int i=0; i<N; i++) {
1879  BinfmtSender<T>::send(stream);
1880  }
1881  }
1882 };
1883 
1884 template <typename T, int N>
1885 struct TextSender<blitz::TinyVector<T, N> > {
1886  static void send(std::ostream &stream, const blitz::TinyVector<T, N> &v) {
1887  for(int i=0; i<N; i++) {
1888  if(i) stream << " ";
1889  TextSender<T>::send(stream, v[i]);
1890  }
1891  }
1892 };
1893 
1894 template <typename T, int N>
1895 struct BinarySender<blitz::TinyVector<T, N> > {
1896  static void send(std::ostream &stream, const blitz::TinyVector<T, N> &v) {
1897  for(int i=0; i<N; i++) {
1898  BinarySender<T>::send(stream, v[i]);
1899  }
1900  }
1901 };
1902 
1903 class Error_WasBlitzPartialSlice { };
1904 
1905 template <typename T, int ArrayDim, int SliceDim>
1906 class BlitzIterator {
1907 public:
1908  BlitzIterator() : p(NULL) { }
1909  BlitzIterator(
1910  const blitz::Array<T, ArrayDim> *_p,
1911  const blitz::TinyVector<int, ArrayDim> _idx
1912  ) : p(_p), idx(_idx) { }
1913 
1914  typedef Error_WasBlitzPartialSlice value_type;
1915  typedef BlitzIterator<T, ArrayDim, SliceDim-1> subiter_type;
1916  static const bool is_container = true;
1917 
1918  // FIXME - it would be nice to also handle one-based arrays
1919  bool is_end() const {
1920  return idx[ArrayDim-SliceDim] == p->shape()[ArrayDim-SliceDim];
1921  }
1922 
1923  void inc() {
1924  ++idx[ArrayDim-SliceDim];
1925  }
1926 
1927  value_type deref() const {
1928  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "cannot deref a blitz slice");
1929  throw std::logic_error("static assert should have been triggered by this point");
1930  }
1931 
1932  subiter_type deref_subiter() const {
1933  return BlitzIterator<T, ArrayDim, SliceDim-1>(p, idx);
1934  }
1935 
1936 private:
1937  const blitz::Array<T, ArrayDim> *p;
1938  blitz::TinyVector<int, ArrayDim> idx;
1939 };
1940 
1941 template <typename T, int ArrayDim>
1942 class BlitzIterator<T, ArrayDim, 1> {
1943 public:
1944  BlitzIterator() : p(NULL) { }
1945  BlitzIterator(
1946  const blitz::Array<T, ArrayDim> *_p,
1947  const blitz::TinyVector<int, ArrayDim> _idx
1948  ) : p(_p), idx(_idx) { }
1949 
1950  typedef T value_type;
1951  typedef Error_WasNotContainer subiter_type;
1952  static const bool is_container = false;
1953 
1954  // FIXME - it would be nice to also handle one-based arrays
1955  bool is_end() const {
1956  return idx[ArrayDim-1] == p->shape()[ArrayDim-1];
1957  }
1958 
1959  void inc() {
1960  ++idx[ArrayDim-1];
1961  }
1962 
1963  value_type deref() const {
1964  return (*p)(idx);
1965  }
1966 
1967  subiter_type deref_subiter() const {
1968  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "argument was not a container");
1969  throw std::logic_error("static assert should have been triggered by this point");
1970  }
1971 
1972 private:
1973  const blitz::Array<T, ArrayDim> *p;
1974  blitz::TinyVector<int, ArrayDim> idx;
1975 };
1976 
1977 template <typename T, int ArrayDim>
1978 class ArrayTraits<blitz::Array<T, ArrayDim> > : public ArrayTraitsDefaults<T> {
1979 public:
1980  static const bool allow_auto_unwrap = false;
1981  static const size_t depth = ArrayTraits<T>::depth + ArrayDim;
1982 
1983  typedef BlitzIterator<T, ArrayDim, ArrayDim> range_type;
1984 
1985  static range_type get_range(const blitz::Array<T, ArrayDim> &arg) {
1986  blitz::TinyVector<int, ArrayDim> start_idx;
1987  start_idx = 0;
1988  return range_type(&arg, start_idx);
1989  }
1990 };
1991 
1992 } // namespace gnuplotio
1993 #endif // GNUPLOT_BLITZ_SUPPORT_LOADED
1994 #endif // BZ_BLITZ_H
1995 
1996 // }}}2
1997 
1998 // {{{2 Armadillo support
1999 
2000 // This is outside of the main header guard so that it will be compiled when people do
2001 // something like this:
2002 // #include "gnuplot-iostream.h"
2003 // #include <armadillo>
2004 // #include "gnuplot-iostream.h"
2005 // Note that it has its own header guard to avoid double inclusion.
2006 
2007 #ifdef ARMA_INCLUDES
2008 #ifndef GNUPLOT_ARMADILLO_SUPPORT_LOADED
2009 #define GNUPLOT_ARMADILLO_SUPPORT_LOADED
2010 namespace gnuplotio {
2011 
2012 template <typename T> struct dont_treat_as_stl_container<arma::Row <T> > { typedef boost::mpl::bool_<true> type; };
2013 template <typename T> struct dont_treat_as_stl_container<arma::Col <T> > { typedef boost::mpl::bool_<true> type; };
2014 template <typename T> struct dont_treat_as_stl_container<arma::Mat <T> > { typedef boost::mpl::bool_<true> type; };
2015 template <typename T> struct dont_treat_as_stl_container<arma::Cube <T> > { typedef boost::mpl::bool_<true> type; };
2016 template <typename T> struct dont_treat_as_stl_container<arma::field<T> > { typedef boost::mpl::bool_<true> type; };
2017 
2018 // {{{3 Cube
2019 
2020 template <typename T>
2021 class ArrayTraits<arma::Cube<T> > : public ArrayTraitsDefaults<T> {
2022  class SliceRange {
2023  public:
2024  SliceRange() : p(NULL), col(0), slice(0) { }
2025  explicit SliceRange(const arma::Cube<T> *_p, size_t _row, size_t _col) :
2026  p(_p), row(_row), col(_col), slice(0) { }
2027 
2028  typedef T value_type;
2029  typedef Error_WasNotContainer subiter_type;
2030  static const bool is_container = false;
2031 
2032  bool is_end() const { return slice == p->n_slices; }
2033 
2034  void inc() { ++slice; }
2035 
2036  value_type deref() const {
2037  return (*p)(row, col, slice);
2038  }
2039 
2040  subiter_type deref_subiter() const {
2041  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "argument was not a container");
2042  throw std::logic_error("static assert should have been triggered by this point");
2043  }
2044 
2045  private:
2046  const arma::Cube<T> *p;
2047  size_t row, col, slice;
2048  };
2049 
2050  class ColRange {
2051  public:
2052  ColRange() : p(NULL), row(0), col(0) { }
2053  explicit ColRange(const arma::Cube<T> *_p, size_t _row) :
2054  p(_p), row(_row), col(0) { }
2055 
2056  typedef T value_type;
2057  typedef SliceRange subiter_type;
2058  static const bool is_container = true;
2059 
2060  bool is_end() const { return col == p->n_cols; }
2061 
2062  void inc() { ++col; }
2063 
2064  value_type deref() const {
2065  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "can't call deref on an armadillo cube col");
2066  throw std::logic_error("static assert should have been triggered by this point");
2067  }
2068 
2069  subiter_type deref_subiter() const {
2070  return subiter_type(p, row, col);
2071  }
2072 
2073  private:
2074  const arma::Cube<T> *p;
2075  size_t row, col;
2076  };
2077 
2078  class RowRange {
2079  public:
2080  RowRange() : p(NULL), row(0) { }
2081  explicit RowRange(const arma::Cube<T> *_p) : p(_p), row(0) { }
2082 
2083  typedef T value_type;
2084  typedef ColRange subiter_type;
2085  static const bool is_container = true;
2086 
2087  bool is_end() const { return row == p->n_rows; }
2088 
2089  void inc() { ++row; }
2090 
2091  value_type deref() const {
2092  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "can't call deref on an armadillo cube row");
2093  throw std::logic_error("static assert should have been triggered by this point");
2094  }
2095 
2096  subiter_type deref_subiter() const {
2097  return subiter_type(p, row);
2098  }
2099 
2100  private:
2101  const arma::Cube<T> *p;
2102  size_t row;
2103  };
2104 
2105 public:
2106  static const bool allow_auto_unwrap = false;
2107  static const size_t depth = ArrayTraits<T>::depth + 3;
2108 
2109  typedef RowRange range_type;
2110 
2111  static range_type get_range(const arma::Cube<T> &arg) {
2112  //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl;
2113  return range_type(&arg);
2114  }
2115 };
2116 
2117 // }}}3
2118 
2119 // {{{3 Mat and Field
2120 
2121 template <typename RF, typename T>
2122 class ArrayTraits_ArmaMatOrField : public ArrayTraitsDefaults<T> {
2123  class ColRange {
2124  public:
2125  ColRange() : p(NULL), row(0), col(0) { }
2126  explicit ColRange(const RF *_p, size_t _row) :
2127  p(_p), row(_row), col(0) { }
2128 
2129  typedef T value_type;
2130  typedef Error_WasNotContainer subiter_type;
2131  static const bool is_container = false;
2132 
2133  bool is_end() const { return col == p->n_cols; }
2134 
2135  void inc() { ++col; }
2136 
2137  value_type deref() const {
2138  return (*p)(row, col);
2139  }
2140 
2141  subiter_type deref_subiter() const {
2142  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "argument was not a container");
2143  throw std::logic_error("static assert should have been triggered by this point");
2144  }
2145 
2146  private:
2147  const RF *p;
2148  size_t row, col;
2149  };
2150 
2151  class RowRange {
2152  public:
2153  RowRange() : p(NULL), row(0) { }
2154  explicit RowRange(const RF *_p) : p(_p), row(0) { }
2155 
2156  typedef T value_type;
2157  typedef ColRange subiter_type;
2158  static const bool is_container = true;
2159 
2160  bool is_end() const { return row == p->n_rows; }
2161 
2162  void inc() { ++row; }
2163 
2164  value_type deref() const {
2165  GNUPLOT_STATIC_ASSERT_MSG((sizeof(T) == 0), "can't call deref on an armadillo matrix row");
2166  throw std::logic_error("static assert should have been triggered by this point");
2167  }
2168 
2169  subiter_type deref_subiter() const {
2170  return subiter_type(p, row);
2171  }
2172 
2173  private:
2174  const RF *p;
2175  size_t row;
2176  };
2177 
2178 public:
2179  static const bool allow_auto_unwrap = false;
2180  static const size_t depth = ArrayTraits<T>::depth + 2;
2181 
2182  typedef RowRange range_type;
2183 
2184  static range_type get_range(const RF &arg) {
2185  //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl;
2186  return range_type(&arg);
2187  }
2188 };
2189 
2190 template <typename T>
2191 class ArrayTraits<arma::field<T> > : public ArrayTraits_ArmaMatOrField<arma::field<T>, T> { };
2192 
2193 template <typename T>
2194 class ArrayTraits<arma::Mat<T> > : public ArrayTraits_ArmaMatOrField<arma::Mat<T>, T> { };
2195 
2196 // }}}3
2197 
2198 // {{{3 Row
2199 
2200 template <typename T>
2201 class ArrayTraits<arma::Row<T> > : public ArrayTraitsDefaults<T> {
2202 public:
2203  static const bool allow_auto_unwrap = false;
2204 
2206 
2207  static range_type get_range(const arma::Row<T> &arg) {
2208  //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl;
2209  return range_type(arg.begin(), arg.end());
2210  }
2211 };
2212 
2213 // }}}3
2214 
2215 // {{{3 Col
2216 
2217 template <typename T>
2218 class ArrayTraits<arma::Col<T> > : public ArrayTraitsDefaults<T> {
2219 public:
2220  static const bool allow_auto_unwrap = false;
2221 
2223 
2224  static range_type get_range(const arma::Col<T> &arg) {
2225  //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl;
2226  return range_type(arg.begin(), arg.end());
2227  }
2228 };
2229 
2230 // }}}3
2231 
2232 } // namespace gnuplotio
2233 #endif // GNUPLOT_ARMADILLO_SUPPORT_LOADED
2234 #endif // ARMA_INCLUDES
2235 
2236 // }}}2
2237 
2238 // }}}1
static range_type get_range(const T &)
VecOfRange< typename ArrayTraits< T >::range_type::subiter_type > get_columns_range(const T &arg)
Gnuplot & send(const T &arg, OrganizationMode)
void send_scalar(std::ostream &stream, const T &arg, ModeText)
filename
IteratorRange< typename T::const_iterator, typename T::value_type > range_type
boost::mpl::and_< typename has_head_type< T >::type, typename has_tail_type< T >::type > type
static void send(std::ostream &stream)
static void send(std::ostream &stream)
static std::string class_name()
static void send(std::ostream &stream, const T &v)
#define GNUPLOT_STATIC_ASSERT_MSG(cond, msg)
Gnuplot & sendBinary(const T &arg, OrganizationMode)
#define GNUPLOT_PCLOSE
static bool debug_array_print
static void send(std::ostream &stream, const std::pair< T, U > &v)
boost::disable_if_c< T::is_container >::type deref_and_print(std::ostream &stream, const T &arg, PrintMode)
Gnuplot(const std::string &_cmd="")
PairOfRange(const RT &_l, const RU &_r)
std::string make_tmpfile()
static void send(std::ostream &stream)
static std::string class_name()
#define GNUPLOT_MSVC_WARNING_4996_POP
IteratorRange(const TI &_it, const TI &_end)
boost::mpl::if_c< is_container, Error_InappropriateDeref, TV >::type value_type
static std::string get_default_cmd()
static std::string class_name()
static range_type get_range(const std::pair< T, U > &arg)
#define GNUPLOT_FILENO
std::vector< RT > rvec
static std::string class_name()
std::string binfmt(const T &arg, const std::string &arr_or_rec, OrganizationMode)
size_t get_range_size(const T &arg)
value_type deref() const
std::string binaryFile(const T &arg, std::string filename, const std::string &arr_or_rec, OrganizationMode)
FileHandleWrapper(std::FILE *_fh, bool _should_use_pclose)
static void send(std::ostream &stream)
subiter_type deref_subiter() const
std::vector< int > tmp_files
static range_type get_range(const T(&arg)[N])
static void send(std::ostream &stream)
boost::mpl::and_< typename has_value_type< T >::type, typename has_const_iterator< T >::type, boost::mpl::not_< dont_treat_as_stl_container< T > > > type
Error_WasNotContainer value_type
static void send(std::ostream &stream, const T &v)
PairOfRange< typename RT::subiter_type, typename RU::subiter_type > subiter_type
boost::mpl::bool_< value > type
ArrayTraits< TV >::range_type subiter_type
void top_level_array_sender(std::ostream &stream, const T &arg, OrganizationMode, PrintMode)
static void send(std::ostream &)
static void send(std::ostream &stream)
subiter_type deref_subiter() const
#define GNUPLOT_DEPRECATE(msg)
VecOfRange(const std::vector< RT > &_rvec)
Gnuplot GNUPLOT_DEPRECATE("use send1d or send2d")&send(const T &arg)
std::pair< typename ArrayTraits< T >::value_type, typename ArrayTraits< U >::value_type > value_type
std::vector< typename RT::value_type > value_type
std::string file(const T &arg, std::string filename, OrganizationMode)
static void send(std::ostream &stream, const T &v)
static void send(std::ostream &stream, const std::complex< T > &v)
#define GNUPLOT_ISNAN
void handle_colunwrap_tag(std::ostream &stream, const T &arg, ColUnwrapNo, PrintMode)
static void send(std::ostream &stream)
static void send(std::ostream &stream)
static void send(std::ostream &stream, const T &v)
static void send(std::ostream &stream, const std::pair< T, U > &v)
void handle_organization_tag(std::ostream &stream, const T &arg, Mode1D, PrintMode)
Error_WasNotContainer range_type
static FileHandleWrapper open_cmdline(const std::string &in)
PairOfRange< typename ArrayTraits< T >::range_type, typename ArrayTraits< U >::range_type > range_type
VecOfRange< typename RT::subiter_type > subiter_type
static void send(std::ostream &stream, const T &v)
#define GNUPLOT_MSVC_WARNING_4996_PUSH
value_type deref() const
subiter_type deref_subiter() const
IteratorRange< const T *, T > range_type
static void send(std::ostream &stream)
boost::enable_if_c<(Depth==1)&&!PrintMode::is_size >::type print_block(std::ostream &stream, T &arg, PrintMode)
value_type deref() const
std::pair< typename RT::value_type, typename RU::value_type > value_type
static void send(std::ostream &stream)
static void send(std::ostream &stream)
static void send(std::ostream &stream)
#define GNUPLOT_POPEN
static std::string class_name()
#define GNUPLOT_DEFAULT_COMMAND
static void send(std::ostream &stream, const std::complex< T > &v)


asr_psm_visualizations
Author(s): Gehrung Joachim, Meißner Pascal
autogenerated on Sat Nov 9 2019 03:49:13