diff --git a/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o b/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o index 928d673..de6a8e7 100644 Binary files a/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o and b/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o differ diff --git a/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o.d b/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o.d index 510c284..3058386 100644 --- a/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o.d +++ b/build/CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o.d @@ -185,6 +185,554 @@ CMakeFiles/HLlib.dir/src/HiddenLines.cpp.o: \ /usr/include/c++/11.2.0/bits/stl_bvector.h \ /usr/include/c++/11.2.0/bits/vector.tcc \ /usr/include/c++/11.2.0/pstl/execution_defs.h \ + /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/gnuplot-iostream.h \ + /usr/include/c++/11.2.0/sstream /usr/include/c++/11.2.0/bits/sstream.tcc \ + /usr/include/c++/11.2.0/iomanip /usr/include/c++/11.2.0/locale \ + /usr/include/c++/11.2.0/bits/locale_facets_nonio.h \ + /usr/include/c++/11.2.0/ctime \ + /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/time_members.h \ + /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/messages_members.h \ + /usr/include/libintl.h \ + /usr/include/c++/11.2.0/bits/locale_facets_nonio.tcc \ + /usr/include/c++/11.2.0/bits/locale_conv.h \ + /usr/include/c++/11.2.0/bits/unique_ptr.h \ + /usr/include/c++/11.2.0/bits/quoted_string.h \ + /usr/include/c++/11.2.0/complex \ + /usr/include/boost/iostreams/device/file_descriptor.hpp \ + /usr/include/boost/cstdint.hpp /usr/include/boost/config.hpp \ + /usr/include/boost/config/user.hpp \ + /usr/include/boost/config/detail/select_compiler_config.hpp \ + /usr/include/boost/config/compiler/gcc.hpp \ + /usr/include/c++/11.2.0/cstddef \ + /usr/include/boost/config/detail/select_stdlib_config.hpp \ + /usr/include/c++/11.2.0/version \ + /usr/include/boost/config/stdlib/libstdcpp3.hpp /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + /usr/include/linux/close_range.h \ + /usr/include/boost/config/detail/select_platform_config.hpp \ + /usr/include/boost/config/platform/linux.hpp \ + /usr/include/boost/config/detail/posix_features.hpp \ + /usr/include/boost/config/detail/suffix.hpp \ + /usr/include/boost/config/helper_macros.hpp \ + /usr/include/boost/config/detail/cxx_composite.hpp \ + /usr/include/boost/iostreams/categories.hpp \ + /usr/include/boost/iostreams/detail/config/auto_link.hpp \ + /usr/include/boost/config/auto_link.hpp \ + /usr/include/boost/iostreams/detail/config/dyn_link.hpp \ + /usr/include/boost/detail/workaround.hpp \ + /usr/include/boost/config/workaround.hpp \ + /usr/include/boost/iostreams/detail/config/windows_posix.hpp \ + /usr/include/boost/iostreams/detail/file_handle.hpp \ + /usr/include/boost/iostreams/detail/ios.hpp \ + /usr/include/boost/iostreams/detail/config/wide_streams.hpp \ + /usr/include/boost/iostreams/detail/path.hpp \ + /usr/include/c++/11.2.0/cstring /usr/include/string.h \ + /usr/include/strings.h /usr/include/boost/static_assert.hpp \ + /usr/include/boost/type.hpp /usr/include/boost/type_traits/is_same.hpp \ + /usr/include/boost/type_traits/integral_constant.hpp \ + /usr/include/boost/iostreams/positioning.hpp \ + /usr/include/boost/integer_traits.hpp /usr/include/boost/limits.hpp \ + /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/include-fixed/limits.h \ + /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/include-fixed/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h /usr/include/bits/xopen_lim.h \ + /usr/include/bits/uio_lim.h \ + /usr/include/boost/iostreams/detail/config/codecvt.hpp \ + /usr/include/boost/iostreams/detail/config/fpos.hpp \ + /usr/include/boost/iostreams/detail/config/disable_warnings.hpp \ + /usr/include/boost/iostreams/detail/config/enable_warnings.hpp \ + /usr/include/boost/shared_ptr.hpp \ + /usr/include/boost/smart_ptr/shared_ptr.hpp \ + /usr/include/boost/smart_ptr/detail/shared_count.hpp \ + /usr/include/boost/smart_ptr/bad_weak_ptr.hpp \ + /usr/include/boost/smart_ptr/detail/sp_counted_base.hpp \ + /usr/include/boost/smart_ptr/detail/sp_has_gcc_intrinsics.hpp \ + /usr/include/boost/smart_ptr/detail/sp_has_sync_intrinsics.hpp \ + /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_atomic.hpp \ + /usr/include/boost/smart_ptr/detail/sp_typeinfo_.hpp \ + /usr/include/boost/smart_ptr/detail/sp_counted_impl.hpp \ + /usr/include/boost/smart_ptr/detail/sp_noexcept.hpp \ + /usr/include/boost/checked_delete.hpp \ + /usr/include/boost/core/checked_delete.hpp \ + /usr/include/boost/core/addressof.hpp /usr/include/c++/11.2.0/memory \ + /usr/include/c++/11.2.0/bits/stl_raw_storage_iter.h \ + /usr/include/c++/11.2.0/bits/align.h /usr/include/c++/11.2.0/bit \ + /usr/include/c++/11.2.0/bits/shared_ptr.h \ + /usr/include/c++/11.2.0/bits/shared_ptr_base.h \ + /usr/include/c++/11.2.0/bits/allocated_ptr.h \ + /usr/include/c++/11.2.0/ext/concurrence.h \ + /usr/include/c++/11.2.0/bits/shared_ptr_atomic.h \ + /usr/include/c++/11.2.0/bits/atomic_base.h \ + /usr/include/c++/11.2.0/bits/atomic_lockfree_defines.h \ + /usr/include/c++/11.2.0/backward/auto_ptr.h \ + /usr/include/c++/11.2.0/pstl/glue_memory_defs.h \ + /usr/include/boost/smart_ptr/detail/sp_disable_deprecated.hpp \ + /usr/include/boost/throw_exception.hpp \ + /usr/include/boost/exception/exception.hpp \ + /usr/include/boost/assert/source_location.hpp \ + /usr/include/boost/current_function.hpp \ + /usr/include/boost/smart_ptr/detail/sp_convertible.hpp \ + /usr/include/boost/smart_ptr/detail/sp_nullptr_t.hpp \ + /usr/include/boost/assert.hpp /usr/include/assert.h \ + /usr/include/boost/smart_ptr/detail/spinlock_pool.hpp \ + /usr/include/boost/smart_ptr/detail/spinlock.hpp \ + /usr/include/boost/smart_ptr/detail/spinlock_gcc_atomic.hpp \ + /usr/include/boost/smart_ptr/detail/yield_k.hpp \ + /usr/include/boost/smart_ptr/detail/sp_thread_pause.hpp \ + /usr/include/boost/smart_ptr/detail/sp_thread_sleep.hpp \ + /usr/include/boost/config/pragma_message.hpp \ + /usr/include/boost/smart_ptr/detail/operator_bool.hpp \ + /usr/include/boost/smart_ptr/detail/local_sp_deleter.hpp \ + /usr/include/boost/smart_ptr/detail/local_counted_base.hpp \ + /usr/include/boost/config/abi_prefix.hpp \ + /usr/include/boost/config/abi_suffix.hpp \ + /usr/include/boost/iostreams/stream.hpp \ + /usr/include/boost/iostreams/constants.hpp \ + /usr/include/boost/iostreams/detail/char_traits.hpp \ + /usr/include/boost/iostreams/detail/config/overload_resolution.hpp \ + /usr/include/boost/iostreams/detail/config/gcc.hpp \ + /usr/include/boost/iostreams/detail/forward.hpp \ + /usr/include/boost/iostreams/detail/config/limits.hpp \ + /usr/include/boost/iostreams/detail/push_params.hpp \ + /usr/include/boost/preprocessor/arithmetic/dec.hpp \ + /usr/include/boost/preprocessor/config/config.hpp \ + /usr/include/boost/preprocessor/config/limits.hpp \ + /usr/include/boost/preprocessor/arithmetic/limits/dec_256.hpp \ + /usr/include/boost/preprocessor/arithmetic/inc.hpp \ + /usr/include/boost/preprocessor/arithmetic/limits/inc_256.hpp \ + /usr/include/boost/preprocessor/punctuation/comma_if.hpp \ + /usr/include/boost/preprocessor/control/if.hpp \ + /usr/include/boost/preprocessor/control/iif.hpp \ + /usr/include/boost/preprocessor/logical/bool.hpp \ + /usr/include/boost/preprocessor/logical/limits/bool_256.hpp \ + /usr/include/boost/preprocessor/facilities/empty.hpp \ + /usr/include/boost/preprocessor/punctuation/comma.hpp \ + /usr/include/boost/preprocessor/repetition/enum_binary_params.hpp \ + /usr/include/boost/preprocessor/cat.hpp \ + /usr/include/boost/preprocessor/repetition/repeat.hpp \ + /usr/include/boost/preprocessor/debug/error.hpp \ + /usr/include/boost/preprocessor/detail/auto_rec.hpp \ + /usr/include/boost/preprocessor/detail/limits/auto_rec_256.hpp \ + /usr/include/boost/preprocessor/tuple/eat.hpp \ + /usr/include/boost/preprocessor/repetition/limits/repeat_256.hpp \ + /usr/include/boost/preprocessor/tuple/elem.hpp \ + /usr/include/boost/preprocessor/facilities/expand.hpp \ + /usr/include/boost/preprocessor/facilities/overload.hpp \ + /usr/include/boost/preprocessor/variadic/size.hpp \ + /usr/include/boost/preprocessor/facilities/check_empty.hpp \ + /usr/include/boost/preprocessor/variadic/has_opt.hpp \ + /usr/include/boost/preprocessor/variadic/limits/size_64.hpp \ + /usr/include/boost/preprocessor/tuple/rem.hpp \ + /usr/include/boost/preprocessor/tuple/detail/is_single_return.hpp \ + /usr/include/boost/preprocessor/variadic/elem.hpp \ + /usr/include/boost/preprocessor/variadic/limits/elem_64.hpp \ + /usr/include/boost/preprocessor/repetition/enum_params.hpp \ + /usr/include/boost/preprocessor/repetition/repeat_from_to.hpp \ + /usr/include/boost/preprocessor/arithmetic/add.hpp \ + /usr/include/boost/preprocessor/control/while.hpp \ + /usr/include/boost/preprocessor/list/fold_left.hpp \ + /usr/include/boost/preprocessor/list/detail/fold_left.hpp \ + /usr/include/boost/preprocessor/control/expr_iif.hpp \ + /usr/include/boost/preprocessor/list/adt.hpp \ + /usr/include/boost/preprocessor/detail/is_binary.hpp \ + /usr/include/boost/preprocessor/detail/check.hpp \ + /usr/include/boost/preprocessor/logical/compl.hpp \ + /usr/include/boost/preprocessor/list/detail/limits/fold_left_256.hpp \ + /usr/include/boost/preprocessor/list/limits/fold_left_256.hpp \ + /usr/include/boost/preprocessor/list/fold_right.hpp \ + /usr/include/boost/preprocessor/list/detail/fold_right.hpp \ + /usr/include/boost/preprocessor/list/reverse.hpp \ + /usr/include/boost/preprocessor/facilities/identity.hpp \ + /usr/include/boost/preprocessor/list/detail/limits/fold_right_256.hpp \ + /usr/include/boost/preprocessor/logical/bitand.hpp \ + /usr/include/boost/preprocessor/control/detail/while.hpp \ + /usr/include/boost/preprocessor/control/detail/limits/while_256.hpp \ + /usr/include/boost/preprocessor/control/limits/while_256.hpp \ + /usr/include/boost/preprocessor/logical/bitor.hpp \ + /usr/include/boost/preprocessor/arithmetic/detail/is_maximum_number.hpp \ + /usr/include/boost/preprocessor/comparison/equal.hpp \ + /usr/include/boost/preprocessor/comparison/not_equal.hpp \ + /usr/include/boost/preprocessor/comparison/limits/not_equal_256.hpp \ + /usr/include/boost/preprocessor/arithmetic/detail/maximum_number.hpp \ + /usr/include/boost/preprocessor/arithmetic/detail/is_minimum_number.hpp \ + /usr/include/boost/preprocessor/logical/not.hpp \ + /usr/include/boost/preprocessor/arithmetic/sub.hpp \ + /usr/include/boost/preprocessor/logical/and.hpp \ + /usr/include/boost/iostreams/detail/iostream.hpp \ + /usr/include/boost/iostreams/detail/select.hpp \ + /usr/include/boost/type_traits/is_base_and_derived.hpp \ + /usr/include/boost/type_traits/intrinsics.hpp \ + /usr/include/boost/type_traits/detail/config.hpp \ + /usr/include/boost/version.hpp \ + /usr/include/boost/type_traits/remove_cv.hpp \ + /usr/include/boost/mpl/eval_if.hpp /usr/include/boost/mpl/if.hpp \ + /usr/include/boost/mpl/aux_/value_wknd.hpp \ + /usr/include/boost/mpl/aux_/static_cast.hpp \ + /usr/include/boost/mpl/aux_/config/workaround.hpp \ + /usr/include/boost/mpl/aux_/config/integral.hpp \ + /usr/include/boost/mpl/aux_/config/msvc.hpp \ + /usr/include/boost/mpl/aux_/config/eti.hpp \ + /usr/include/boost/mpl/aux_/na_spec.hpp \ + /usr/include/boost/mpl/lambda_fwd.hpp \ + /usr/include/boost/mpl/void_fwd.hpp \ + /usr/include/boost/mpl/aux_/adl_barrier.hpp \ + /usr/include/boost/mpl/aux_/config/adl.hpp \ + /usr/include/boost/mpl/aux_/config/intel.hpp \ + /usr/include/boost/mpl/aux_/config/gcc.hpp \ + /usr/include/boost/mpl/aux_/na.hpp /usr/include/boost/mpl/bool.hpp \ + /usr/include/boost/mpl/bool_fwd.hpp \ + /usr/include/boost/mpl/integral_c_tag.hpp \ + /usr/include/boost/mpl/aux_/config/static_constant.hpp \ + /usr/include/boost/mpl/aux_/na_fwd.hpp \ + /usr/include/boost/mpl/aux_/config/ctps.hpp \ + /usr/include/boost/mpl/aux_/config/lambda.hpp \ + /usr/include/boost/mpl/aux_/config/ttp.hpp \ + /usr/include/boost/mpl/int.hpp /usr/include/boost/mpl/int_fwd.hpp \ + /usr/include/boost/mpl/aux_/nttp_decl.hpp \ + /usr/include/boost/mpl/aux_/config/nttp.hpp \ + /usr/include/boost/mpl/aux_/integral_wrapper.hpp \ + /usr/include/boost/mpl/aux_/lambda_arity_param.hpp \ + /usr/include/boost/mpl/aux_/template_arity_fwd.hpp \ + /usr/include/boost/mpl/aux_/arity.hpp \ + /usr/include/boost/mpl/aux_/config/dtp.hpp \ + /usr/include/boost/mpl/aux_/preprocessor/params.hpp \ + /usr/include/boost/mpl/aux_/config/preprocessor.hpp \ + /usr/include/boost/preprocessor/comma_if.hpp \ + /usr/include/boost/preprocessor/repeat.hpp \ + /usr/include/boost/preprocessor/inc.hpp \ + /usr/include/boost/mpl/aux_/preprocessor/enum.hpp \ + /usr/include/boost/mpl/aux_/preprocessor/def_params_tail.hpp \ + /usr/include/boost/mpl/limits/arity.hpp \ + /usr/include/boost/preprocessor/identity.hpp \ + /usr/include/boost/preprocessor/empty.hpp \ + /usr/include/boost/mpl/aux_/config/overload_resolution.hpp \ + /usr/include/boost/mpl/aux_/lambda_support.hpp \ + /usr/include/boost/mpl/identity.hpp /usr/include/boost/mpl/void.hpp \ + /usr/include/boost/iostreams/stream_buffer.hpp \ + /usr/include/boost/iostreams/detail/streambuf/direct_streambuf.hpp \ + /usr/include/boost/core/typeinfo.hpp \ + /usr/include/boost/core/demangle.hpp /usr/include/c++/11.2.0/cxxabi.h \ + /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/cxxabi_tweaks.h \ + /usr/include/boost/iostreams/detail/error.hpp \ + /usr/include/boost/iostreams/detail/execute.hpp \ + /usr/include/boost/preprocessor/iteration/local.hpp \ + /usr/include/boost/preprocessor/slot/slot.hpp \ + /usr/include/boost/preprocessor/slot/detail/def.hpp \ + /usr/include/boost/utility/result_of.hpp \ + /usr/include/boost/type_traits/is_class.hpp \ + /usr/include/boost/type_traits/is_pointer.hpp \ + /usr/include/boost/type_traits/is_member_function_pointer.hpp \ + /usr/include/boost/type_traits/detail/is_member_function_pointer_cxx_11.hpp \ + /usr/include/boost/type_traits/remove_reference.hpp \ + /usr/include/boost/type_traits/declval.hpp \ + /usr/include/boost/type_traits/add_rvalue_reference.hpp \ + /usr/include/boost/type_traits/is_void.hpp \ + /usr/include/boost/type_traits/is_reference.hpp \ + /usr/include/boost/type_traits/is_lvalue_reference.hpp \ + /usr/include/boost/type_traits/is_rvalue_reference.hpp \ + /usr/include/boost/type_traits/conditional.hpp \ + /usr/include/boost/type_traits/type_identity.hpp \ + /usr/include/boost/core/enable_if.hpp \ + /usr/include/boost/utility/detail/result_of_variadic.hpp \ + /usr/include/boost/preprocessor/iteration/detail/local.hpp \ + /usr/include/boost/preprocessor/iteration/detail/limits/local_256.hpp \ + /usr/include/boost/iostreams/detail/functional.hpp \ + /usr/include/boost/iostreams/close.hpp \ + /usr/include/boost/iostreams/flush.hpp \ + /usr/include/boost/iostreams/detail/dispatch.hpp \ + /usr/include/boost/iostreams/traits.hpp \ + /usr/include/boost/iostreams/detail/bool_trait_def.hpp \ + /usr/include/boost/iostreams/detail/template_params.hpp \ + /usr/include/boost/preprocessor/control/expr_if.hpp \ + /usr/include/boost/type_traits/detail/yes_no_type.hpp \ + /usr/include/boost/iostreams/detail/is_iterator_range.hpp \ + /usr/include/boost/iostreams/detail/select_by_size.hpp \ + /usr/include/boost/iostreams/detail/wrap_unwrap.hpp \ + /usr/include/boost/iostreams/detail/enable_if_stream.hpp \ + /usr/include/boost/utility/enable_if.hpp \ + /usr/include/boost/iostreams/traits_fwd.hpp /usr/include/boost/ref.hpp \ + /usr/include/boost/core/ref.hpp /usr/include/boost/mpl/or.hpp \ + /usr/include/boost/mpl/aux_/config/use_preprocessed.hpp \ + /usr/include/boost/mpl/aux_/nested_type_wknd.hpp \ + /usr/include/boost/mpl/aux_/include_preprocessed.hpp \ + /usr/include/boost/mpl/aux_/config/compiler.hpp \ + /usr/include/boost/preprocessor/stringize.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/or.hpp \ + /usr/include/boost/range/iterator_range.hpp \ + /usr/include/boost/range/iterator_range_core.hpp \ + /usr/include/boost/iterator/iterator_traits.hpp \ + /usr/include/c++/11.2.0/iterator \ + /usr/include/c++/11.2.0/bits/stream_iterator.h \ + /usr/include/boost/iterator/iterator_facade.hpp \ + /usr/include/boost/iterator/interoperable.hpp \ + /usr/include/boost/type_traits/is_convertible.hpp \ + /usr/include/boost/type_traits/is_complete.hpp \ + /usr/include/boost/type_traits/is_function.hpp \ + /usr/include/boost/type_traits/detail/is_function_cxx_11.hpp \ + /usr/include/boost/type_traits/is_array.hpp \ + /usr/include/boost/type_traits/is_arithmetic.hpp \ + /usr/include/boost/type_traits/is_integral.hpp \ + /usr/include/boost/type_traits/is_floating_point.hpp \ + /usr/include/boost/type_traits/is_abstract.hpp \ + /usr/include/boost/type_traits/add_lvalue_reference.hpp \ + /usr/include/boost/type_traits/add_reference.hpp \ + /usr/include/boost/iterator/detail/config_def.hpp \ + /usr/include/boost/iterator/detail/config_undef.hpp \ + /usr/include/boost/iterator/iterator_categories.hpp \ + /usr/include/boost/mpl/placeholders.hpp /usr/include/boost/mpl/arg.hpp \ + /usr/include/boost/mpl/arg_fwd.hpp \ + /usr/include/boost/mpl/aux_/na_assert.hpp \ + /usr/include/boost/mpl/assert.hpp /usr/include/boost/mpl/not.hpp \ + /usr/include/boost/mpl/aux_/yes_no.hpp \ + /usr/include/boost/mpl/aux_/config/arrays.hpp \ + /usr/include/boost/mpl/aux_/config/gpu.hpp \ + /usr/include/boost/mpl/aux_/config/pp_counter.hpp \ + /usr/include/boost/mpl/aux_/arity_spec.hpp \ + /usr/include/boost/mpl/aux_/arg_typedef.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/arg.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/placeholders.hpp \ + /usr/include/boost/iterator/detail/facade_iterator_category.hpp \ + /usr/include/boost/core/use_default.hpp /usr/include/boost/mpl/and.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/and.hpp \ + /usr/include/boost/type_traits/is_const.hpp \ + /usr/include/boost/detail/indirect_traits.hpp \ + /usr/include/boost/type_traits/is_volatile.hpp \ + /usr/include/boost/type_traits/is_member_pointer.hpp \ + /usr/include/boost/type_traits/remove_pointer.hpp \ + /usr/include/boost/detail/select_type.hpp \ + /usr/include/boost/iterator/detail/enable_if.hpp \ + /usr/include/boost/type_traits/add_const.hpp \ + /usr/include/boost/type_traits/add_pointer.hpp \ + /usr/include/boost/type_traits/remove_const.hpp \ + /usr/include/boost/type_traits/is_pod.hpp \ + /usr/include/boost/type_traits/is_scalar.hpp \ + /usr/include/boost/type_traits/is_enum.hpp \ + /usr/include/boost/mpl/always.hpp \ + /usr/include/boost/mpl/aux_/preprocessor/default_params.hpp \ + /usr/include/boost/mpl/apply.hpp /usr/include/boost/mpl/apply_fwd.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/apply_fwd.hpp \ + /usr/include/boost/mpl/apply_wrap.hpp \ + /usr/include/boost/mpl/aux_/has_apply.hpp \ + /usr/include/boost/mpl/has_xxx.hpp \ + /usr/include/boost/mpl/aux_/type_wrapper.hpp \ + /usr/include/boost/mpl/aux_/config/has_xxx.hpp \ + /usr/include/boost/mpl/aux_/config/msvc_typename.hpp \ + /usr/include/boost/preprocessor/array/elem.hpp \ + /usr/include/boost/preprocessor/array/data.hpp \ + /usr/include/boost/preprocessor/array/size.hpp \ + /usr/include/boost/preprocessor/repetition/enum_trailing_params.hpp \ + /usr/include/boost/mpl/aux_/config/has_apply.hpp \ + /usr/include/boost/mpl/aux_/msvc_never_true.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp \ + /usr/include/boost/mpl/lambda.hpp /usr/include/boost/mpl/bind.hpp \ + /usr/include/boost/mpl/bind_fwd.hpp \ + /usr/include/boost/mpl/aux_/config/bind.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/bind_fwd.hpp \ + /usr/include/boost/mpl/next.hpp /usr/include/boost/mpl/next_prior.hpp \ + /usr/include/boost/mpl/aux_/common_name_wknd.hpp \ + /usr/include/boost/mpl/protect.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/bind.hpp \ + /usr/include/boost/mpl/aux_/full_lambda.hpp \ + /usr/include/boost/mpl/quote.hpp \ + /usr/include/boost/mpl/aux_/has_type.hpp \ + /usr/include/boost/mpl/aux_/config/bcc.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/quote.hpp \ + /usr/include/boost/mpl/aux_/template_arity.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/full_lambda.hpp \ + /usr/include/boost/mpl/aux_/preprocessed/gcc/apply.hpp \ + /usr/include/boost/range/functions.hpp \ + /usr/include/boost/range/begin.hpp /usr/include/boost/range/config.hpp \ + /usr/include/boost/range/iterator.hpp \ + /usr/include/boost/range/range_fwd.hpp \ + /usr/include/boost/range/mutable_iterator.hpp \ + /usr/include/boost/range/detail/extract_optional_type.hpp \ + /usr/include/boost/range/detail/msvc_has_iterator_workaround.hpp \ + /usr/include/boost/range/const_iterator.hpp \ + /usr/include/boost/range/end.hpp \ + /usr/include/boost/range/detail/implementation_help.hpp \ + /usr/include/boost/range/detail/common.hpp \ + /usr/include/boost/range/detail/sfinae.hpp \ + /usr/include/boost/range/size.hpp /usr/include/boost/range/size_type.hpp \ + /usr/include/boost/range/difference_type.hpp \ + /usr/include/boost/range/has_range_iterator.hpp \ + /usr/include/boost/range/concepts.hpp \ + /usr/include/boost/concept_check.hpp \ + /usr/include/boost/concept/assert.hpp \ + /usr/include/boost/concept/detail/general.hpp \ + /usr/include/boost/concept/detail/backward_compatibility.hpp \ + /usr/include/boost/concept/detail/has_constraints.hpp \ + /usr/include/boost/type_traits/conversion_traits.hpp \ + /usr/include/boost/concept/usage.hpp \ + /usr/include/boost/concept/detail/concept_def.hpp \ + /usr/include/boost/preprocessor/seq/for_each_i.hpp \ + /usr/include/boost/preprocessor/repetition/for.hpp \ + /usr/include/boost/preprocessor/repetition/detail/for.hpp \ + /usr/include/boost/preprocessor/repetition/detail/limits/for_256.hpp \ + /usr/include/boost/preprocessor/repetition/limits/for_256.hpp \ + /usr/include/boost/preprocessor/seq/seq.hpp \ + /usr/include/boost/preprocessor/seq/elem.hpp \ + /usr/include/boost/preprocessor/seq/limits/elem_256.hpp \ + /usr/include/boost/preprocessor/seq/size.hpp \ + /usr/include/boost/preprocessor/seq/limits/size_256.hpp \ + /usr/include/boost/preprocessor/seq/detail/is_empty.hpp \ + /usr/include/boost/preprocessor/seq/enum.hpp \ + /usr/include/boost/preprocessor/seq/limits/enum_256.hpp \ + /usr/include/boost/concept/detail/concept_undef.hpp \ + /usr/include/boost/iterator/iterator_concepts.hpp \ + /usr/include/boost/range/value_type.hpp \ + /usr/include/boost/range/detail/misc_concept.hpp \ + /usr/include/boost/type_traits/make_unsigned.hpp \ + /usr/include/boost/type_traits/is_signed.hpp \ + /usr/include/c++/11.2.0/climits \ + /usr/include/boost/type_traits/is_unsigned.hpp \ + /usr/include/boost/type_traits/add_volatile.hpp \ + /usr/include/boost/range/detail/has_member_size.hpp \ + /usr/include/boost/utility.hpp \ + /usr/include/boost/utility/base_from_member.hpp \ + /usr/include/boost/utility/binary.hpp \ + /usr/include/boost/preprocessor/control/deduce_d.hpp \ + /usr/include/boost/preprocessor/seq/cat.hpp \ + /usr/include/boost/preprocessor/seq/fold_left.hpp \ + /usr/include/boost/preprocessor/seq/limits/fold_left_256.hpp \ + /usr/include/boost/preprocessor/seq/transform.hpp \ + /usr/include/boost/preprocessor/arithmetic/mod.hpp \ + /usr/include/boost/preprocessor/arithmetic/detail/div_base.hpp \ + /usr/include/boost/preprocessor/comparison/less_equal.hpp \ + /usr/include/boost/preprocessor/arithmetic/detail/is_1_number.hpp \ + /usr/include/boost/utility/identity_type.hpp \ + /usr/include/boost/type_traits/function_traits.hpp \ + /usr/include/boost/core/noncopyable.hpp \ + /usr/include/boost/range/distance.hpp \ + /usr/include/boost/iterator/distance.hpp \ + /usr/include/boost/range/empty.hpp /usr/include/boost/range/rbegin.hpp \ + /usr/include/boost/range/reverse_iterator.hpp \ + /usr/include/boost/iterator/reverse_iterator.hpp \ + /usr/include/boost/iterator/iterator_adaptor.hpp \ + /usr/include/boost/range/rend.hpp \ + /usr/include/boost/range/algorithm/equal.hpp \ + /usr/include/boost/range/detail/safe_bool.hpp \ + /usr/include/boost/next_prior.hpp \ + /usr/include/boost/type_traits/has_plus.hpp \ + /usr/include/boost/type_traits/detail/has_binary_operator.hpp \ + /usr/include/boost/type_traits/make_void.hpp \ + /usr/include/boost/type_traits/has_plus_assign.hpp \ + /usr/include/boost/type_traits/has_minus.hpp \ + /usr/include/boost/type_traits/has_minus_assign.hpp \ + /usr/include/boost/iterator/advance.hpp \ + /usr/include/boost/range/iterator_range_io.hpp \ + /usr/include/boost/iostreams/detail/streambuf.hpp \ + /usr/include/boost/iostreams/operations_fwd.hpp \ + /usr/include/boost/iostreams/detail/adapter/non_blocking_adapter.hpp \ + /usr/include/boost/iostreams/read.hpp \ + /usr/include/boost/iostreams/char_traits.hpp \ + /usr/include/boost/iostreams/seek.hpp \ + /usr/include/boost/iostreams/write.hpp \ + /usr/include/boost/iostreams/detail/optional.hpp \ + /usr/include/boost/type_traits/aligned_storage.hpp \ + /usr/include/boost/type_traits/alignment_of.hpp \ + /usr/include/boost/type_traits/type_with_alignment.hpp \ + /usr/include/boost/iostreams/detail/streambuf/linked_streambuf.hpp \ + /usr/include/boost/iostreams/operations.hpp \ + /usr/include/boost/iostreams/imbue.hpp \ + /usr/include/boost/iostreams/input_sequence.hpp \ + /usr/include/boost/iostreams/optimal_buffer_size.hpp \ + /usr/include/boost/iostreams/output_sequence.hpp \ + /usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp \ + /usr/include/c++/11.2.0/cassert \ + /usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp \ + /usr/include/boost/iostreams/concepts.hpp \ + /usr/include/boost/iostreams/detail/default_arg.hpp \ + /usr/include/boost/iostreams/detail/call_traits.hpp \ + /usr/include/boost/iostreams/detail/config/unreachable_return.hpp \ + /usr/include/boost/iostreams/device/null.hpp \ + /usr/include/boost/iostreams/detail/buffer.hpp \ + /usr/include/boost/iostreams/checked_operations.hpp \ + /usr/include/boost/iostreams/get.hpp \ + /usr/include/boost/iostreams/put.hpp \ + /usr/include/boost/iostreams/detail/double_object.hpp \ + /usr/include/boost/call_traits.hpp \ + /usr/include/boost/detail/call_traits.hpp \ + /usr/include/boost/iostreams/detail/push.hpp \ + /usr/include/boost/iostreams/detail/adapter/range_adapter.hpp \ + /usr/include/boost/iostreams/pipeline.hpp \ + /usr/include/boost/iostreams/detail/resolve.hpp \ + /usr/include/boost/detail/is_incrementable.hpp \ + /usr/include/boost/type_traits/detail/bool_trait_undef.hpp \ + /usr/include/boost/iostreams/detail/adapter/mode_adapter.hpp \ + /usr/include/boost/iostreams/detail/adapter/output_iterator_adapter.hpp \ + /usr/include/boost/iostreams/detail/is_dereferenceable.hpp \ + /usr/include/boost/iostreams/device/array.hpp \ + /usr/include/boost/tuple/tuple.hpp \ + /usr/include/boost/tuple/detail/tuple_basic.hpp \ + /usr/include/boost/type_traits/cv_traits.hpp \ + /usr/include/boost/type_traits/add_cv.hpp \ + /usr/include/boost/type_traits/remove_volatile.hpp \ + /usr/include/boost/utility/swap.hpp /usr/include/boost/core/swap.hpp \ + /usr/include/boost/filesystem.hpp \ + /usr/include/boost/filesystem/config.hpp \ + /usr/include/boost/system/api_config.hpp \ + /usr/include/boost/filesystem/path.hpp \ + /usr/include/boost/filesystem/path_traits.hpp \ + /usr/include/boost/system/error_category.hpp \ + /usr/include/boost/system/detail/error_category.hpp \ + /usr/include/boost/system/detail/config.hpp \ + /usr/include/c++/11.2.0/atomic \ + /usr/include/boost/system/detail/error_category_impl.hpp \ + /usr/include/boost/system/detail/error_condition.hpp \ + /usr/include/boost/system/detail/generic_category.hpp \ + /usr/include/boost/system/detail/generic_category_message.hpp \ + /usr/include/boost/system/detail/enable_if.hpp \ + /usr/include/boost/system/detail/is_same.hpp \ + /usr/include/boost/system/detail/errc.hpp \ + /usr/include/boost/system/is_error_condition_enum.hpp \ + /usr/include/boost/system/detail/cerrno.hpp \ + /usr/include/boost/system/detail/append_int.hpp \ + /usr/include/boost/system/detail/snprintf.hpp \ + /usr/include/c++/11.2.0/cstdarg \ + /usr/include/boost/system/detail/error_code.hpp \ + /usr/include/boost/system/is_error_code_enum.hpp \ + /usr/include/boost/system/detail/system_category.hpp \ + /usr/include/boost/system/detail/system_category_impl.hpp \ + /usr/include/boost/system/detail/interop_category.hpp \ + /usr/include/boost/system/detail/std_category.hpp \ + /usr/include/boost/type_traits/decay.hpp \ + /usr/include/boost/type_traits/remove_bounds.hpp \ + /usr/include/boost/type_traits/remove_extent.hpp \ + /usr/include/c++/11.2.0/list /usr/include/c++/11.2.0/bits/stl_list.h \ + /usr/include/c++/11.2.0/bits/list.tcc \ + /usr/include/boost/filesystem/detail/header.hpp \ + /usr/include/boost/filesystem/detail/footer.hpp \ + /usr/include/boost/io/quoted.hpp \ + /usr/include/boost/io/detail/buffer_fill.hpp \ + /usr/include/boost/io/detail/ostream_guard.hpp \ + /usr/include/boost/io/ios_state.hpp /usr/include/boost/io_fwd.hpp \ + /usr/include/boost/functional/hash_fwd.hpp \ + /usr/include/boost/container_hash/hash_fwd.hpp \ + /usr/include/boost/filesystem/exception.hpp \ + /usr/include/boost/system/error_code.hpp \ + /usr/include/boost/system/error_condition.hpp \ + /usr/include/boost/system/errc.hpp \ + /usr/include/boost/system/generic_category.hpp \ + /usr/include/boost/system/system_category.hpp \ + /usr/include/boost/system/detail/throws.hpp \ + /usr/include/boost/system/system_error.hpp \ + /usr/include/boost/smart_ptr/intrusive_ptr.hpp \ + /usr/include/boost/config/no_tr1/functional.hpp \ + /usr/include/boost/smart_ptr/intrusive_ref_counter.hpp \ + /usr/include/boost/smart_ptr/detail/atomic_count.hpp \ + /usr/include/boost/smart_ptr/detail/atomic_count_gcc_atomic.hpp \ + /usr/include/boost/filesystem/directory.hpp \ + /usr/include/boost/filesystem/file_status.hpp \ + /usr/include/boost/detail/bitmask.hpp \ + /usr/include/boost/core/scoped_enum.hpp \ + /usr/include/boost/filesystem/operations.hpp \ + /usr/include/boost/filesystem/convenience.hpp \ + /usr/include/boost/filesystem/string_file.hpp \ + /usr/include/boost/filesystem/fstream.hpp \ /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/HiddenLines.h \ /usr/include/c++/11.2.0/map /usr/include/c++/11.2.0/bits/stl_map.h \ /usr/include/c++/11.2.0/bits/stl_multimap.h \ diff --git a/build/CMakeFiles/linelib.dir/compiler_depend.internal b/build/CMakeFiles/linelib.dir/compiler_depend.internal index 3367adb..34e0779 100644 --- a/build/CMakeFiles/linelib.dir/compiler_depend.internal +++ b/build/CMakeFiles/linelib.dir/compiler_depend.internal @@ -5,17 +5,4 @@ CMakeFiles/linelib.dir/src/Line.cpp.o /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/Line.cpp /usr/include/stdc-predef.h /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/Line.h - /usr/include/c++/11.2.0/limits - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/c++config.h - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/os_defines.h - /usr/include/features.h - /usr/include/features-time64.h - /usr/include/bits/wordsize.h - /usr/include/bits/timesize.h - /usr/include/sys/cdefs.h - /usr/include/bits/long-double.h - /usr/include/gnu/stubs.h - /usr/include/gnu/stubs-64.h - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/cpu_defines.h - /usr/include/c++/11.2.0/pstl/pstl_config.h diff --git a/build/CMakeFiles/linelib.dir/compiler_depend.make b/build/CMakeFiles/linelib.dir/compiler_depend.make index d84048d..10d2aae 100644 --- a/build/CMakeFiles/linelib.dir/compiler_depend.make +++ b/build/CMakeFiles/linelib.dir/compiler_depend.make @@ -3,50 +3,11 @@ CMakeFiles/linelib.dir/src/Line.cpp.o: ../src/Line.cpp \ /usr/include/stdc-predef.h \ - ../src/Line.h \ - /usr/include/c++/11.2.0/limits \ - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/c++config.h \ - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/os_defines.h \ - /usr/include/features.h \ - /usr/include/features-time64.h \ - /usr/include/bits/wordsize.h \ - /usr/include/bits/timesize.h \ - /usr/include/sys/cdefs.h \ - /usr/include/bits/long-double.h \ - /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h \ - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/cpu_defines.h \ - /usr/include/c++/11.2.0/pstl/pstl_config.h + ../src/Line.h -/usr/include/c++/11.2.0/pstl/pstl_config.h: - -/usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/cpu_defines.h: - -/usr/include/c++/11.2.0/limits: - -/usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/os_defines.h: - -/usr/include/stdc-predef.h: - -/usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/c++config.h: - -/usr/include/gnu/stubs-64.h: - -/usr/include/bits/timesize.h: - ../src/Line.h: -/usr/include/features.h: - -/usr/include/features-time64.h: +/usr/include/stdc-predef.h: ../src/Line.cpp: - -/usr/include/bits/wordsize.h: - -/usr/include/sys/cdefs.h: - -/usr/include/bits/long-double.h: - -/usr/include/gnu/stubs.h: diff --git a/build/CMakeFiles/linelib.dir/src/Line.cpp.o.d b/build/CMakeFiles/linelib.dir/src/Line.cpp.o.d index bdf6cbf..9fa47ca 100644 --- a/build/CMakeFiles/linelib.dir/src/Line.cpp.o.d +++ b/build/CMakeFiles/linelib.dir/src/Line.cpp.o.d @@ -1,13 +1,4 @@ CMakeFiles/linelib.dir/src/Line.cpp.o: \ /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/Line.cpp \ /usr/include/stdc-predef.h \ - /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/Line.h \ - /usr/include/c++/11.2.0/limits \ - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/c++config.h \ - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/os_defines.h \ - /usr/include/features.h /usr/include/features-time64.h \ - /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ - /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/cpu_defines.h \ - /usr/include/c++/11.2.0/pstl/pstl_config.h + /home/noah/Documents/School/CS-7353_Analysis-of-Algorithms/HW/HW4/src/Line.h diff --git a/build/libHLlib.a b/build/libHLlib.a index 680b9cb..c28bfef 100644 Binary files a/build/libHLlib.a and b/build/libHLlib.a differ diff --git a/build/main b/build/main index b722624..32012b9 100755 Binary files a/build/main and b/build/main differ diff --git a/src/HiddenLines.cpp b/src/HiddenLines.cpp index 76cd1b1..9117850 100644 --- a/src/HiddenLines.cpp +++ b/src/HiddenLines.cpp @@ -9,6 +9,7 @@ #include #include +#include "gnuplot-iostream.h" #include "HiddenLines.h" HL::HL() @@ -17,8 +18,8 @@ HL::HL() lines = construct_HWprob(); } -void print_sol(std::vector& lines) -{ +//Print the solution and convert the double::max and double::lowest to inf strings +void print_sol(std::vector& lines){ for(auto itr = lines.begin(); itr != lines.end(); itr++){ Line line = *itr; double start_range = line.get_vis_start(); @@ -104,6 +105,7 @@ std::vector HL::gen_sol(std::vector& ls){ } } +//Read from CSV file to construct this problem. Use std::set to order std::vector HL::construct_HWprob(){ //Set to hold all our Lines std::set sorted_lines; @@ -168,6 +170,7 @@ std::vector HL::construct_HWprob(){ return lines; } +//Merge the two halves and set visible start and end points std::vector merge(std::vector lh, std::vector rh){ std::vector merged; @@ -190,7 +193,6 @@ std::vector merge(std::vector lh, std::vector rh){ *ritr = l2; } merged.push_back(l1); - //merged.push_back(l2); litr++; } @@ -207,7 +209,6 @@ std::vector merge(std::vector lh, std::vector rh){ *litr = l1; merged.push_back(l2); } - litr++; ritr++; } @@ -243,6 +244,11 @@ std::vector HL::get_lines(){ return lines; } +/* +// Line merging process merges the two halves and keeps the order, but does not check for +// when intersection points fall to the left (more negative) of other intersection points. +// Need to remove the invisible lines caused by this case. +*/ std::vector remove_invis(std::vector &merged){ //Create separate visible line holder @@ -253,36 +259,37 @@ std::vector remove_invis(std::vector &merged){ merged.erase(merged.begin()); tmp_vis.push_back(merged.front()); merged.erase(merged.begin()); - int num_vis = 2; //Loop through the remainder of the original vector for(Line &line : merged){ //Pull out the back two lines - Line last = tmp_vis.at(num_vis -1); - Line seclast = tmp_vis.at(num_vis -2); + Line last = tmp_vis.at(tmp_vis.size()-1); + Line seclast = tmp_vis.at(tmp_vis.size()-2); //Intersection of our "known" visible lines vs the intersection of the 2nd to last vis line and the original vec double vis_isec = last.get_isec(seclast); double merg_isec = line.get_isec(seclast); while(merg_isec < vis_isec){ - //line intersects before the last line, and since line slope > last line slope, remove it - tmp_vis.erase(tmp_vis.begin() + (num_vis -1)); - num_vis--; + //Adjust visibility start and end points line.set_vis_start(merg_isec); + seclast.set_vis_end(merg_isec); + tmp_vis.at(tmp_vis.size()-2) = seclast; - if(num_vis == 1) + //line intersects before the last line, and since line slope > last line slope, remove it + tmp_vis.erase(tmp_vis.begin() + (tmp_vis.size()-1)); + + //We only have 1 line visible, no more comparisons needed to see if we have something out of order + if(tmp_vis.size() == 1) break; - last = tmp_vis.at(num_vis -1); - seclast = tmp_vis.at(num_vis -2); + //Otherwise, get our next lines to make sure we don't have something + last = tmp_vis.at(tmp_vis.size()-1); + seclast = tmp_vis.at(tmp_vis.size()-2); vis_isec = last.get_isec(seclast); merg_isec = line.get_isec(seclast); } - tmp_vis.push_back(line); - num_vis++; } - return tmp_vis; } diff --git a/src/Line.cpp b/src/Line.cpp index a85a089..b1a035c 100644 --- a/src/Line.cpp +++ b/src/Line.cpp @@ -1,8 +1,6 @@ //Line Class #include "Line.h" -#include - int Line::current_id = 0; @@ -11,8 +9,8 @@ Line::Line(double x, double y) set_slope(x); set_ycept(y); id = 0; - //set_vis_start(-std::numeric_limits::max()); - //set_vis_end(std::numeric_limits::max()); + + //Arbitrarily just say lines are visible starting at and ending at 0. set_vis_start(0); set_vis_end(0); } diff --git a/src/gnuplot-iostream.h b/src/gnuplot-iostream.h new file mode 100644 index 0000000..42be0fb --- /dev/null +++ b/src/gnuplot-iostream.h @@ -0,0 +1,2586 @@ +// vim:foldmethod=marker + +/* +Copyright (c) 2020 Daniel Stahlke (dan@stahlke.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* A C++ interface to gnuplot. + * Web page: http://www.stahlke.org/dan/gnuplot-iostream + * Documentation: https://github.com/dstahlke/gnuplot-iostream/wiki + * + * The whole library consists of this monolithic header file, for ease of installation (the + * Makefile and *.cc files are only for examples and tests). + * + * TODO: + * Callbacks via gnuplot's 'bind' function. This would allow triggering user functions when + * keys are pressed in the gnuplot window. However, it would require a PTY reader thread. + * Maybe temporary files read in a thread can replace PTY stuff. + */ + +#ifndef GNUPLOT_IOSTREAM_H +#define GNUPLOT_IOSTREAM_H + +// {{{1 Includes and defines + +#define GNUPLOT_IOSTREAM_VERSION 3 + +// C system includes +#include +#ifdef GNUPLOT_ENABLE_PTY +# include +# include +#ifdef __APPLE__ +# include +#else +# include +#endif +#endif // GNUPLOT_ENABLE_PTY + +// C++ system includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +// This is the version of boost which has v3 of the filesystem libraries by default. +#if BOOST_VERSION >= 104600 +# define GNUPLOT_USE_TMPFILE +# include +#endif // BOOST_VERSION + +// Note: this is here for reverse compatibility. The new way to enable blitz support is to +// just include the gnuplot-iostream.h header after you include the blitz header (likewise for +// armadillo). +#ifdef GNUPLOT_ENABLE_BLITZ +# include +#endif + +// If this is defined, warn about use of deprecated functions. +#ifdef GNUPLOT_DEPRECATE_WARN +# ifdef __GNUC__ +# define GNUPLOT_DEPRECATE(msg) __attribute__ ((deprecated(msg))) +# elif defined(_MSC_VER) +# define GNUPLOT_DEPRECATE(msg) __declspec(deprecated(msg)) +# else +# define GNUPLOT_DEPRECATE(msg) +# endif +#else +# define GNUPLOT_DEPRECATE(msg) +#endif + +// Patch for Windows by Damien Loison +#ifdef _WIN32 +# include +# define GNUPLOT_PCLOSE _pclose +# define GNUPLOT_POPEN _popen +# define GNUPLOT_FILENO _fileno +#else +# define GNUPLOT_PCLOSE pclose +# define GNUPLOT_POPEN popen +# define GNUPLOT_FILENO fileno +#endif + +#ifdef _WIN32 +# define GNUPLOT_ISNAN _isnan +#else +// cppreference.com says std::isnan is only for C++11. However, this seems to work on Linux +// and I am assuming that if isnan exists in math.h then std::isnan exists in cmath. +# define GNUPLOT_ISNAN std::isnan +#endif + +// MSVC gives a warning saying that fopen and getenv are not secure. But they are secure. +// Unfortunately their replacement functions are not simple drop-in replacements. The best +// solution is to just temporarily disable this warning whenever fopen or getenv is used. +// http://stackoverflow.com/a/4805353/1048959 +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define GNUPLOT_MSVC_WARNING_4996_PUSH \ + __pragma(warning(push)) \ + __pragma(warning(disable:4996)) +# define GNUPLOT_MSVC_WARNING_4996_POP \ + __pragma(warning(pop)) +#else +# define GNUPLOT_MSVC_WARNING_4996_PUSH +# define GNUPLOT_MSVC_WARNING_4996_POP +#endif + +#ifndef GNUPLOT_DEFAULT_COMMAND +#ifdef _WIN32 +// "pgnuplot" is considered deprecated according to the Internet. It may be faster. It +// doesn't seem to handle binary data though. +//# define GNUPLOT_DEFAULT_COMMAND "pgnuplot -persist" +// On Windows, gnuplot echos commands to stderr. So we forward its stderr to the bit bucket. +// Unfortunately, this means you will miss out on legitimate error messages. +# define GNUPLOT_DEFAULT_COMMAND "gnuplot -persist 2> NUL" +#else +# define GNUPLOT_DEFAULT_COMMAND "gnuplot -persist" +#endif +#endif + +// }}}1 + +namespace gnuplotio { + +// {{{1 Basic traits helpers +// +// The mechanisms constructed in this section enable us to detect what sort of datatype has +// been passed to a function. + +// This can be specialized as needed, in order to not use the STL interfaces for specific +// classes. +template +static constexpr bool dont_treat_as_stl_container = false; + + +template +static constexpr bool is_like_stl_container = false; + +template +static constexpr bool is_like_stl_container().begin()), + decltype(std::declval().end()), + typename T::value_type + >> = !dont_treat_as_stl_container; + +static_assert( is_like_stl_container>); +static_assert(!is_like_stl_container); + + +template +static constexpr bool is_like_stl_container2 = false; + +template +static constexpr bool is_like_stl_container2())), + decltype(end (std::declval())) + >> = !is_like_stl_container && !dont_treat_as_stl_container; + + +template +static constexpr bool is_boost_tuple_nulltype = + std::is_same_v; + +static_assert(is_boost_tuple_nulltype); + +template +static constexpr bool is_boost_tuple = false; + +template +static constexpr bool is_boost_tuple> = is_boost_tuple || is_boost_tuple_nulltype; + +static_assert( is_boost_tuple>); +static_assert( is_boost_tuple>); +static_assert(!is_boost_tuple>); +static_assert(!is_boost_tuple>); + +// }}}1 + +// {{{1 Tmpfile helper class +#ifdef GNUPLOT_USE_TMPFILE +// RAII temporary file. File is removed when this object goes out of scope. +class GnuplotTmpfile { +public: + explicit GnuplotTmpfile(bool _debug_messages) : + file(boost::filesystem::unique_path( + boost::filesystem::temp_directory_path() / + "tmp-gnuplot-%%%%-%%%%-%%%%-%%%%")), + debug_messages(_debug_messages) + { + if(debug_messages) { + std::cerr << "create tmpfile " << file << std::endl; + } + } + +private: + // noncopyable + GnuplotTmpfile(const GnuplotTmpfile &); + const GnuplotTmpfile& operator=(const GnuplotTmpfile &); + +public: + ~GnuplotTmpfile() { + if(debug_messages) { + std::cerr << "delete tmpfile " << file << std::endl; + } + // it is never good to throw exceptions from a destructor + try { + remove(file); + } catch(const std::exception &) { + std::cerr << "Failed to remove temporary file " << file << std::endl; + } + } + +public: + boost::filesystem::path file; + bool debug_messages; +}; + +class GnuplotTmpfileCollection { +public: + std::string make_tmpfile() { + const bool debug_messages = false; + std::shared_ptr tmp_file(new GnuplotTmpfile(debug_messages)); + // The file will be removed once the pointer is removed from the + // tmp_files container. + tmp_files.push_back(tmp_file); + return tmp_file->file.string(); + } + + void clear() { + tmp_files.clear(); + } + +private: + std::vector> tmp_files; +}; +#else // GNUPLOT_USE_TMPFILE +class GnuplotTmpfileCollection { +public: + std::string make_tmpfile() { + throw std::logic_error("no filename given and temporary files not enabled"); + } + + void clear() { } +}; +#endif // GNUPLOT_USE_TMPFILE +// }}}1 + +// {{{1 Feedback helper classes +// +// Used for reading stuff sent from gnuplot via gnuplot's "print" function. +// +// For example, this is used for capturing mouse clicks in the gnuplot window. There are two +// implementations, only the first of which is complete. The first implementation allocates a +// PTY (pseudo terminal) which is written to by gnuplot and read by us. This only works in +// Linux. The second implementation creates a temporary file which is written to by gnuplot +// and read by us. However, this doesn't currently work since fscanf doesn't block. It would +// be possible to get this working using a more complicated mechanism (select or threads) but I +// haven't had the need for it. + +class GnuplotFeedback { +public: + GnuplotFeedback() { } + virtual ~GnuplotFeedback() { } + virtual std::string filename() const = 0; + virtual FILE *handle() const = 0; + +private: + // noncopyable + GnuplotFeedback(const GnuplotFeedback &); + const GnuplotFeedback& operator=(const GnuplotFeedback &); +}; + +#ifdef GNUPLOT_ENABLE_PTY +#define GNUPLOT_ENABLE_FEEDBACK +class GnuplotFeedbackPty : public GnuplotFeedback { +public: + explicit GnuplotFeedbackPty(bool debug_messages) : + pty_fn(), + pty_fh(nullptr), + master_fd(-1), + slave_fd(-1) + { + // adapted from http://www.gnuplot.info/files/gpReadMouseTest.c + if(0 > openpty(&master_fd, &slave_fd, nullptr, nullptr, nullptr)) { + perror("openpty"); + throw std::runtime_error("openpty failed"); + } + char pty_fn_buf[1024]; + if(ttyname_r(slave_fd, pty_fn_buf, 1024)) { + perror("ttyname_r"); + throw std::runtime_error("ttyname failed"); + } + pty_fn = std::string(pty_fn_buf); + if(debug_messages) { + std::cerr << "feedback_fn=" << pty_fn << std::endl; + } + + // disable echo + struct termios tios; + if(tcgetattr(slave_fd, &tios) < 0) { + perror("tcgetattr"); + throw std::runtime_error("tcgetattr failed"); + } + tios.c_lflag &= ~(ECHO | ECHONL); + if(tcsetattr(slave_fd, TCSAFLUSH, &tios) < 0) { + perror("tcsetattr"); + throw std::runtime_error("tcsetattr failed"); + } + + pty_fh = fdopen(master_fd, "r"); + if(!pty_fh) { + throw std::runtime_error("fdopen failed"); + } + } + +private: + // noncopyable + GnuplotFeedbackPty(const GnuplotFeedbackPty &); + const GnuplotFeedbackPty& operator=(const GnuplotFeedbackPty &); + +public: + ~GnuplotFeedbackPty() { + if(pty_fh) fclose(pty_fh); + if(master_fd > 0) ::close(master_fd); + if(slave_fd > 0) ::close(slave_fd); + } + + std::string filename() const { + return pty_fn; + } + + FILE *handle() const { + return pty_fh; + } + +private: + std::string pty_fn; + FILE *pty_fh; + int master_fd, slave_fd; +}; +//#elif defined GNUPLOT_USE_TMPFILE +//// Currently this doesn't work since fscanf doesn't block (need something like "tail -f") +//#define GNUPLOT_ENABLE_FEEDBACK +//class GnuplotFeedbackTmpfile : public GnuplotFeedback { +//public: +// explicit GnuplotFeedbackTmpfile(bool debug_messages) : +// tmp_file(), +// fh(nullptr) +// { +// if(debug_messages) { +// std::cerr << "feedback_fn=" << filename() << std::endl; +// } +// GNUPLOT_MSVC_WARNING_4996_PUSH +// fh = std::fopen(filename().c_str(), "a"); +// GNUPLOT_MSVC_WARNING_4996_POP +// } +// +// ~GnuplotFeedbackTmpfile() { +// fclose(fh); +// } +// +//private: +// // noncopyable +// GnuplotFeedbackTmpfile(const GnuplotFeedbackTmpfile &); +// const GnuplotFeedbackTmpfile& operator=(const GnuplotFeedbackTmpfile &); +// +//public: +// std::string filename() const { +// return tmp_file.file.string(); +// } +// +// FILE *handle() const { +// return fh; +// } +// +//private: +// GnuplotTmpfile tmp_file; +// FILE *fh; +//}; +#endif // GNUPLOT_ENABLE_PTY, GNUPLOT_USE_TMPFILE +// }}}1 + +// {{{1 Traits and printers for entry datatypes +// +// This section contains the mechanisms for sending scalar and tuple data to gnuplot. Pairs +// and tuples are sent by appealing to the senders defined for their component scalar types. +// Senders for arrays are defined in a later section. +// +// There are three classes which need to be specialized for each supported datatype: +// 1. TextSender to send data as text. The default is to just send using the ostream's `<<` +// operator. +// 2. BinarySender to send data as binary, in a format which gnuplot can understand. There is +// no default implementation (unimplemented types raise a compile time error), however +// inheriting from FlatBinarySender will send the data literally as it is stored in memory. +// This suffices for most of the standard built-in types (e.g. uint32_t or double). +// 3. BinfmtSender sends a description of the data format to gnuplot (e.g. `%uint32`). Type +// `show datafile binary datasizes` in gnuplot to see a list of supported formats. + +// {{{2 Basic entry datatypes + +// Default TextSender, sends data using `<<` operator. +template +struct TextSender { + static void send(std::ostream &stream, const T &v) { + stream << v; + } +}; + +class BinarySenderNotImplemented : public std::logic_error { +public: + explicit BinarySenderNotImplemented(const std::string &w) : std::logic_error(w) { } +}; + +// Default BinarySender, raises a compile time error. +template +struct BinarySender { + static void send(std::ostream &, const T &) { + throw BinarySenderNotImplemented("BinarySender not implemented for this type"); + } +}; + +// This is a BinarySender implementation that just sends directly from memory. Data types +// which can be sent this way can have their BinarySender specialization inherit from this. +template +struct FlatBinarySender { + static void send(std::ostream &stream, const T &v) { + stream.write(reinterpret_cast(&v), sizeof(T)); + } +}; + +// Default BinfmtSender, raises a compile time error. +template +struct BinfmtSender { + static void send(std::ostream &) { + throw BinarySenderNotImplemented("BinfmtSender not implemented for this type"); + } +}; + +// BinfmtSender implementations for basic data types supported by gnuplot. +template<> struct BinfmtSender< float> { static void send(std::ostream &stream) { stream << "%float"; } }; +template<> struct BinfmtSender { static void send(std::ostream &stream) { stream << "%double"; } }; +template<> struct BinfmtSender< int8_t> { static void send(std::ostream &stream) { stream << "%int8"; } }; +template<> struct BinfmtSender< uint8_t> { static void send(std::ostream &stream) { stream << "%uint8"; } }; +template<> struct BinfmtSender< int16_t> { static void send(std::ostream &stream) { stream << "%int16"; } }; +template<> struct BinfmtSender { static void send(std::ostream &stream) { stream << "%uint16"; } }; +template<> struct BinfmtSender< int32_t> { static void send(std::ostream &stream) { stream << "%int32"; } }; +template<> struct BinfmtSender { static void send(std::ostream &stream) { stream << "%uint32"; } }; +template<> struct BinfmtSender< int64_t> { static void send(std::ostream &stream) { stream << "%int64"; } }; +template<> struct BinfmtSender { static void send(std::ostream &stream) { stream << "%uint64"; } }; + +// BinarySender implementations for basic data types supported by gnuplot. These types can +// just be sent as stored in memory, so all these senders inherit from FlatBinarySender. +template<> struct BinarySender< float> : public FlatBinarySender< float> { }; +template<> struct BinarySender : public FlatBinarySender { }; +template<> struct BinarySender< int8_t> : public FlatBinarySender< int8_t> { }; +template<> struct BinarySender< uint8_t> : public FlatBinarySender< uint8_t> { }; +template<> struct BinarySender< int16_t> : public FlatBinarySender< int16_t> { }; +template<> struct BinarySender : public FlatBinarySender { }; +template<> struct BinarySender< int32_t> : public FlatBinarySender< int32_t> { }; +template<> struct BinarySender : public FlatBinarySender { }; +template<> struct BinarySender< int64_t> : public FlatBinarySender< int64_t> { }; +template<> struct BinarySender : public FlatBinarySender { }; + +// Make char types print as integers, not as characters. +template +struct CastIntTextSender { + static void send(std::ostream &stream, const T &v) { + stream << static_cast(v); + } +}; +template<> struct TextSender< char> : public CastIntTextSender< char> { }; +template<> struct TextSender< signed char> : public CastIntTextSender< signed char> { }; +template<> struct TextSender< unsigned char> : public CastIntTextSender< unsigned char> { }; + +// Make sure that the same not-a-number string is printed on all platforms. +template +struct FloatTextSender { + static void send(std::ostream &stream, const T &v) { + if(GNUPLOT_ISNAN(v)) { stream << "nan"; } else { stream << v; } + } +}; +template<> struct TextSender< float> : FloatTextSender< float> { }; +template<> struct TextSender< double> : FloatTextSender< double> { }; +template<> struct TextSender : FloatTextSender { }; + +// }}}2 + +// {{{2 std::pair support + +template +struct TextSender> { + static void send(std::ostream &stream, const std::pair &v) { + TextSender::send(stream, v.first); + stream << " "; + TextSender::send(stream, v.second); + } +}; + +template +struct BinfmtSender> { + static void send(std::ostream &stream) { + BinfmtSender::send(stream); + BinfmtSender::send(stream); + } +}; + +template +struct BinarySender> { + static void send(std::ostream &stream, const std::pair &v) { + BinarySender::send(stream, v.first); + BinarySender::send(stream, v.second); + } +}; + +// }}}2 + +// {{{2 std::complex support + +template +struct TextSender> { + static void send(std::ostream &stream, const std::complex &v) { + TextSender::send(stream, v.real()); + stream << " "; + TextSender::send(stream, v.imag()); + } +}; + +template +struct BinfmtSender> { + static void send(std::ostream &stream) { + BinfmtSender::send(stream); + BinfmtSender::send(stream); + } +}; + +template +struct BinarySender> { + static void send(std::ostream &stream, const std::complex &v) { + BinarySender::send(stream, v.real()); + BinarySender::send(stream, v.imag()); + } +}; + +// }}}2 + +// {{{2 boost::tuple support + +template +struct TextSender> +> { + static void send(std::ostream &stream, const T &v) { + TextSender::send(stream, v.get_head()); + if constexpr (!is_boost_tuple_nulltype) { + stream << " "; + TextSender::send(stream, v.get_tail()); + } + } +}; + +template +struct BinfmtSender> +> { + static void send(std::ostream &stream) { + BinfmtSender::send(stream); + if constexpr (!is_boost_tuple_nulltype) { + stream << " "; + BinfmtSender::send(stream); + } + } +}; + +template +struct BinarySender> +> { + static void send(std::ostream &stream, const T &v) { + BinarySender::send(stream, v.get_head()); + if constexpr (!is_boost_tuple_nulltype) { + BinarySender::send(stream, v.get_tail()); + } + } +}; + +// }}}2 + +// {{{2 std::tuple support + +// http://stackoverflow.com/questions/6245735/pretty-print-stdtuple + +template struct int_{}; // compile-time counter + +template +void std_tuple_formatcode_helper(std::ostream &stream, const Tuple *, int_) { + std_tuple_formatcode_helper(stream, (const Tuple *)(0), int_()); + stream << " "; + BinfmtSender::type>::send(stream); +} + +template +void std_tuple_formatcode_helper(std::ostream &stream, const Tuple *, int_<0>) { + BinfmtSender::type>::send(stream); +} + +template +struct BinfmtSender> { + typedef typename std::tuple Tuple; + + static void send(std::ostream &stream) { + std_tuple_formatcode_helper(stream, (const Tuple *)(0), int_()); + } +}; + +template +void std_tuple_textsend_helper(std::ostream &stream, const Tuple &v, int_) { + std_tuple_textsend_helper(stream, v, int_()); + stream << " "; + TextSender::type>::send(stream, std::get(v)); +} + +template +void std_tuple_textsend_helper(std::ostream &stream, const Tuple &v, int_<0>) { + TextSender::type>::send(stream, std::get<0>(v)); +} + +template +struct TextSender> { + typedef typename std::tuple Tuple; + + static void send(std::ostream &stream, const Tuple &v) { + std_tuple_textsend_helper(stream, v, int_()); + } +}; + +template +void std_tuple_binsend_helper(std::ostream &stream, const Tuple &v, int_) { + std_tuple_binsend_helper(stream, v, int_()); + BinarySender::type>::send(stream, std::get(v)); +} + +template +void std_tuple_binsend_helper(std::ostream &stream, const Tuple &v, int_<0>) { + BinarySender::type>::send(stream, std::get<0>(v)); +} + +template +struct BinarySender> { + typedef typename std::tuple Tuple; + + static void send(std::ostream &stream, const Tuple &v) { + std_tuple_binsend_helper(stream, v, int_()); + } +}; + +// }}}2 + +// }}}1 + +// {{{1 ArrayTraits and Range classes +// +// This section handles sending of array data to gnuplot. It is rather complicated because of +// the diversity of storage schemes supported. For example, it treats a +// `std::pair, std::vector>` in the same way as a +// `std::vector>`, iterating through the two arrays in lockstep, and sending +// pairs to gnuplot as columns. In fact, any nested combination of pairs, tuples, STL +// containers, Blitz arrays, and Armadillo arrays is supported (with the caveat that, for +// instance, Blitz arrays should never be put into an STL container or you will suffer +// unpredictable results due the way Blitz handles assignment). Nested containers are +// considered to be multidimensional arrays. Although gnuplot only supports 1D and 2D arrays, +// our module is in principle not limited. +// +// The ArrayTraits class is specialized for every supported array or container type (the +// default, unspecialized, version of ArrayTraits exists only to tell you that something is +// *not* a container, via the is_container flag). ArrayTraits tells you the depth of a nested +// (or multidimensional) container, as well as the value type, and provides a specialized +// sort of iterator (a.k.a. "range"). Ranges are sort of like STL iterators, except that they +// have built-in knowledge of the end condition so you don't have to carry around both a +// begin() and an end() iterator like in STL. +// +// As an example of how this works, consider a std::pair of std::vectors. Ultimately this gets +// sent to gnuplot as two columns, so the two vectors need to be iterated in lockstep. +// The `value_type` of `std::pair, std::vector>` is then `std::pair` +// and this is what deferencing the range (iterator) gives. Internally, this range is built +// out of a pair of ranges (PairOfRange class), the `inc()` (advance to next element) +// method calls `inc()` on each of the children, and `deref()` calls `deref()` on each child +// and combines the results to return a `std::pair`. Tuples are handled as nested pairs. +// +// In addition to PairOfRange, there is also a VecOfRange class that can be used to treat the +// outermost part of a nested container as if it were a tuple. Since tuples are printed as +// columns, this is like treating a multidimensional array as if it were column-major. A +// VecOfRange is obtained by calling `get_columns_range`. This is used by, for instance, +// `send1d_colmajor`. The implementation is similar to that of PairOfRange. +// +// The range, accessed via `ArrayTraits::get_range`, will be of a different class depending +// on T, and this is defined by the ArrayTraits specialization for T. It will always have +// methods `inc()` to advance to the next element and `is_end()` for checking whether one has +// advanced past the final element. For nested containers, `deref_subiter()` returns a range +// iterator for the next nesting level. When at the innermost level of nesting, `deref()` +// returns the value of the entry the iterator points to (a scalar, pair, or tuple). +// Only one of `deref()` or `deref_subiter()` will be available, depending on whether there are +// deeper levels of nesting. The typedefs `value_type` and `subiter_type` tell the return +// types of these two methods. +// +// Support for standard C++ and boost containers and tuples of containers is provided in this +// section. Support for third party packages like Blitz and Armadillo is in a later section. + +// {{{2 ArrayTraits generic class and defaults + +// Error messages involving this stem from treating something that was not a container as if it +// was. This is only here to allow compiliation without errors in normal cases. +struct Error_WasNotContainer { + // This is just here to make VC++ happy. + // https://connect.microsoft.com/VisualStudio/feedback/details/777612/class-template-specialization-that-compiles-in-g-but-not-visual-c + typedef void subiter_type; +}; + +// The unspecialized version of this class gives traits for things that are *not* arrays. +template +class ArrayTraits { +public: + // The value type of elements after all levels of nested containers have been dereferenced. + typedef Error_WasNotContainer value_type; + // The type of the range (a.k.a. iterator) that `get_range()` returns. + typedef Error_WasNotContainer range_type; + // Tells whether T is in fact a container type. + static constexpr bool is_container = false; + // This flag supports the legacy behavior of automatically guessing whether the data should + // be treated as column major. This guessing happens when `send()` is called rather than + // `send1d()` or `send2d()`. This is deprecated, but is still supported for reverse + // compatibility. + static constexpr bool allow_auto_unwrap = false; + // The number of levels of nesting, or the dimension of multidimensional arrays. + static constexpr size_t depth = 0; + + // Returns the range (iterator) for an array. + static range_type get_range(const T &) { + static_assert((sizeof(T)==0), "argument was not a container"); + throw std::logic_error("static assert should have been triggered by this point"); + } +}; + +// Most specializations of ArrayTraits should inherit from this (with V set to the value type). +// It sets some default values. +template +class ArrayTraitsDefaults { +public: + typedef V value_type; + + static constexpr bool is_container = true; + static constexpr bool allow_auto_unwrap = true; + static constexpr size_t depth = ArrayTraits::depth + 1; +}; + +// This handles reference types, such as are given with std::tie. +// It also allows for instance "ArrayTraits" to match "ArrayTraits". +// I think this is okay to do... The alternative is to use remove_reference all over the place. +template +class ArrayTraits : public ArrayTraits { }; + +// This supports gp.send1d(std::forward_as_tuple(x, std::move(y))); +template +class ArrayTraits : public ArrayTraits { }; + +// }}}2 + +// {{{2 STL container support + +template +class IteratorRange { +public: + IteratorRange() { } + IteratorRange(const TI &_it, const TI &_end) : it(_it), end(_end) { } + + static constexpr bool is_container = ArrayTraits::is_container; + + // Error messages involving this stem from calling deref instead of deref_subiter for a nested + // container. + struct Error_InappropriateDeref { }; + using value_type = typename std::conditional_t; + + using subiter_type = typename ArrayTraits::range_type; + + bool is_end() const { return it == end; } + + void inc() { ++it; } + + value_type deref() const { + static_assert(sizeof(TV) && !is_container, + "deref called on nested container"); + if(is_end()) { + throw std::runtime_error("attepted to dereference past end of iterator"); + } + return *it; + } + + subiter_type deref_subiter() const { + static_assert(sizeof(TV) && is_container, + "deref_subiter called on non-nested container"); + if(is_end()) { + throw std::runtime_error("attepted to dereference past end of iterator"); + } + return ArrayTraits::get_range(*it); + } + +private: + TI it, end; +}; + +template +class ArrayTraits> +> : public ArrayTraitsDefaults { +public: + typedef IteratorRange range_type; + + static range_type get_range(const T &arg) { + return range_type(arg.begin(), arg.end()); + } +}; + +template +class ArrayTraits> +> : public ArrayTraitsDefaults()))>::value_type> { + using IterType = decltype(begin(std::declval())); + using ValType = typename std::iterator_traits::value_type; +public: + typedef IteratorRange range_type; + + static range_type get_range(const T &arg) { + return range_type(begin(arg), end(arg)); + } +}; + +// }}}2 + +// {{{2 C style array support + +template +class ArrayTraits : public ArrayTraitsDefaults { +public: + typedef IteratorRange range_type; + + static range_type get_range(const T (&arg)[N]) { + return range_type(arg, arg+N); + } +}; + +// }}}2 + +// {{{2 std::pair support + +template +class PairOfRange { + template + friend void deref_and_print(std::ostream &, const PairOfRange &, PrintMode); + +public: + PairOfRange() { } + PairOfRange(const RT &_l, const RU &_r) : l(_l), r(_r) { } + + static constexpr bool is_container = RT::is_container && RU::is_container; + + typedef std::pair value_type; + typedef PairOfRange subiter_type; + + bool is_end() const { + bool el = l.is_end(); + bool er = r.is_end(); + if(el != er) { + throw std::length_error("columns were different lengths"); + } + return el; + } + + void inc() { + l.inc(); + r.inc(); + } + + value_type deref() const { + return std::make_pair(l.deref(), r.deref()); + } + + subiter_type deref_subiter() const { + return subiter_type(l.deref_subiter(), r.deref_subiter()); + } + +private: + RT l; + RU r; +}; + +template +class ArrayTraits> { +public: + typedef PairOfRange::range_type, typename ArrayTraits::range_type> range_type; + typedef std::pair::value_type, typename ArrayTraits::value_type> value_type; + static constexpr bool is_container = ArrayTraits::is_container && ArrayTraits::is_container; + // Don't allow colwrap since it's already wrapped. + static constexpr bool allow_auto_unwrap = false; + // It is allowed for l_depth != r_depth, for example one column could be 'double' and the + // other column could be 'vector'. + static constexpr size_t l_depth = ArrayTraits::depth; + static constexpr size_t r_depth = ArrayTraits::depth; + static constexpr size_t depth = (l_depth < r_depth) ? l_depth : r_depth; + + static range_type get_range(const std::pair &arg) { + return range_type( + ArrayTraits::get_range(arg.first), + ArrayTraits::get_range(arg.second) + ); + } +}; + +// }}}2 + +// {{{2 boost::tuple support + +template +class ArrayTraits && !is_boost_tuple_nulltype + > +> : public ArrayTraits< + typename std::pair< + typename T::head_type, + typename T::tail_type + > +> { +public: + typedef typename T::head_type HT; + typedef typename T::tail_type TT; + + typedef ArrayTraits> parent; + + static typename parent::range_type get_range(const T &arg) { + return typename parent::range_type( + ArrayTraits::get_range(arg.get_head()), + ArrayTraits::get_range(arg.get_tail()) + ); + } +}; + +template +class ArrayTraits && is_boost_tuple_nulltype + > +> : public ArrayTraits< + typename T::head_type +> { + typedef typename T::head_type HT; + + typedef ArrayTraits parent; + +public: + static typename parent::range_type get_range(const T &arg) { + return parent::get_range(arg.get_head()); + } +}; + +// }}}2 + +// {{{2 std::tuple support + +template +struct StdTupUnwinder { + typedef std::pair< + typename StdTupUnwinder::type, + typename std::tuple_element::type + > type; + + static typename ArrayTraits::range_type get_range(const Tuple &arg) { + return typename ArrayTraits::range_type( + StdTupUnwinder::get_range(arg), + ArrayTraits::type>::get_range(std::get(arg)) + ); + } +}; + +template +struct StdTupUnwinder { + typedef typename std::tuple_element<0, Tuple>::type type; + + static typename ArrayTraits::range_type get_range(const Tuple &arg) { + return ArrayTraits::get_range(std::get<0>(arg)); + } +}; + +template +class ArrayTraits> : + public ArrayTraits, sizeof...(Args)-1>::type> +{ + typedef std::tuple Tuple; + typedef ArrayTraits::type> parent; + +public: + static typename parent::range_type get_range(const Tuple &arg) { + return StdTupUnwinder, sizeof...(Args)-1>::get_range(arg); + } +}; + +// }}}2 + +// {{{2 Support column unwrap of container (VecOfRange) +// +// VecOfRange (created via `get_columns_range()`) treats the outermost level of a nested +// container as if it were a tuple. Since tuples are sent to gnuplot as columns, this has the +// effect of addressing a multidimensional array in column major order. + +template +class VecOfRange { + template + friend void deref_and_print(std::ostream &, const VecOfRange &, PrintMode); + +public: + VecOfRange() { } + explicit VecOfRange(const std::vector &_rvec) : rvec(_rvec) { } + + static constexpr bool is_container = RT::is_container; + // Don't allow colwrap since it's already wrapped. + static constexpr bool allow_auto_unwrap = false; + + typedef std::vector value_type; + typedef VecOfRange subiter_type; + + bool is_end() const { + if(rvec.empty()) return true; + bool ret = rvec[0].is_end(); + for(size_t i=1; i subvec(rvec.size()); + for(size_t i=0; i rvec; +}; + +template +VecOfRange::range_type::subiter_type> +get_columns_range(const T &arg) { + typedef typename ArrayTraits::range_type::subiter_type U; + std::vector rvec; + typename ArrayTraits::range_type outer = ArrayTraits::get_range(arg); + while(!outer.is_end()) { + rvec.push_back(outer.deref_subiter()); + outer.inc(); + } + VecOfRange ret(rvec); + return ret; +} + +// }}}2 + +// }}}1 + +// {{{1 Array printing functions +// +// This section coordinates the sending of data to gnuplot. The ArrayTraits mechanism tells us +// about nested containers and provides iterators over them. Here we make use of this, +// deciding what dimensions should be treated as rows, columns, or blocks, telling gnuplot the +// size of the array if needed, and so on. + +// If this is set, then text-mode data will be sent in a format that is not compatible with +// gnuplot, but which helps the programmer tell what the library is thinking. Basically it +// puts brackets around groups of items and puts a message delineating blocks of data. +static bool debug_array_print = 0; + +// This is thrown when an empty container is being plotted. This exception should always +// be caught and should not propagate to the user. +class plotting_empty_container : public std::length_error { +public: + plotting_empty_container() : std::length_error("plotting empty container") { } +}; + +// {{{2 Tags (like enums for metaprogramming) + +// These tags define what our goal is, what sort of thing should ultimately be sent to the +// ostream. These tags are passed to the PrintMode template argument of the functions in this +// section. +// +// ModeText - Sends the data in an array in text format +// ModeBinary - Sends the data in an array in binary format +// ModeBinfmt - Sends the gnuplot format code for binary data (e.g. "%double%double") +// ModeSize - Sends the size of an array. Needed when sending binary data. +struct ModeText { static constexpr bool is_text = 1; static constexpr bool is_binfmt = 0; static constexpr bool is_size = 0; }; +struct ModeBinary { static constexpr bool is_text = 0; static constexpr bool is_binfmt = 0; static constexpr bool is_size = 0; }; +struct ModeBinfmt { static constexpr bool is_text = 0; static constexpr bool is_binfmt = 1; static constexpr bool is_size = 0; }; +struct ModeSize { static constexpr bool is_text = 0; static constexpr bool is_binfmt = 0; static constexpr bool is_size = 1; }; + +// Whether to treat the outermost level of a nested container as columns (column major mode). +struct ColUnwrapNo { }; +struct ColUnwrapYes { }; + +// The user must give a hint to describe how nested containers are to be interpreted. This is +// done by calling e.g. `send1d_colmajor()` or `send2d()`. This hint is then described by the +// following tags. This is passed to the OrganizationMode template argument. +struct Mode1D { static std::string class_name() { return "Mode1D" ; } }; +struct Mode2D { static std::string class_name() { return "Mode2D" ; } }; +struct Mode1DUnwrap { static std::string class_name() { return "Mode1DUnwrap"; } }; +struct Mode2DUnwrap { static std::string class_name() { return "Mode2DUnwrap"; } }; +// Support for the legacy behavior that guesses which of the above four modes should be used. +struct ModeAuto { static std::string class_name() { return "ModeAuto" ; } }; + +// }}}2 + +// {{{2 ModeAutoDecoder +// +// ModeAuto guesses which of Mode1D, Mode2D, Mode1DUnwrap, or Mode2DUnwrap should be used. +// This is provided for reverse compatibility; it is better to specify explicitly which mode to +// use. Since this is only for reverse compatibility, and shouldn't be used, I'm not going to +// spell out what the rules are. See below for details. + +template +struct ModeAutoDecoder { }; + +template +struct ModeAutoDecoder::depth == 1) + >> +{ + typedef Mode1D mode; +}; + +template +struct ModeAutoDecoder::depth == 2) && + !ArrayTraits::allow_auto_unwrap + >> +{ + typedef Mode2D mode; +}; + +template +struct ModeAutoDecoder::depth == 2) && + ArrayTraits::allow_auto_unwrap + >> +{ + typedef Mode1DUnwrap mode; +}; + +template +struct ModeAutoDecoder::depth > 2) && + ArrayTraits::allow_auto_unwrap + >> +{ + typedef Mode2DUnwrap mode; +}; + +template +struct ModeAutoDecoder::depth > 2) && + !ArrayTraits::allow_auto_unwrap + >> +{ + typedef Mode2D mode; +}; + +// }}}2 + +// The data is processed using several levels of functions that call each other in sequence, +// each defined in a subsection of code below. Because C++ wants you to declare a function +// before using it, we begin with the innermost function. So in order to see the sequence in +// which these are called, you should read the following subsections in reverse order. Nested +// arrays are formated into blocks (for 2D data) and lines (for 1D or 2D data), then further +// nesting levels are formatted into columns. Also tag dispatching is used in order to define +// various sorts of behavior. Each of these tasks is handled by one of the following +// subsections. + +// {{{2 send_scalar() +// +// Send a scalar in one of three possible ways: via TextSender, BinarySender, or BinfmtSender, +// depending on which PrintMode tag is passed to the function. + +template +void send_scalar(std::ostream &stream, const T &arg, ModeText) { + TextSender::send(stream, arg); +} + +template +void send_scalar(std::ostream &stream, const T &arg, ModeBinary) { + BinarySender::send(stream, arg); +} + +template +void send_scalar(std::ostream &stream, const T &, ModeBinfmt) { + BinfmtSender::send(stream); +} + +// }}}2 + +// {{{2 deref_and_print() +// +// Dereferences and prints the given range (iterator). At this point we are done with treating +// containers as blocks (for 2D data) and lines (for 1D or 2D data). Any further levels of +// nested containers will at this point be treated as columns. + +// If arg is not a container, then print it via send_scalar(). +template +typename std::enable_if_t +deref_and_print(std::ostream &stream, const T &arg, PrintMode) { + const typename T::value_type &v = arg.deref(); + send_scalar(stream, v, PrintMode()); +} + +// If arg is a container (but not a PairOfRange or VecOfRange, which are handled below) then +// treat the contents as columns, iterating over the contents recursively. If outputting in +// text mode, put a space between columns. +template +typename std::enable_if_t +deref_and_print(std::ostream &stream, const T &arg, PrintMode) { + if(arg.is_end()) throw plotting_empty_container(); + typename T::subiter_type subrange = arg.deref_subiter(); + if(PrintMode::is_binfmt && subrange.is_end()) throw plotting_empty_container(); + if(debug_array_print && PrintMode::is_text) stream << "{"; + bool first = true; + while(!subrange.is_end()) { + if(!first && PrintMode::is_text) stream << " "; + first = false; + deref_and_print(stream, subrange, PrintMode()); + subrange.inc(); + } + if(debug_array_print && PrintMode::is_text) stream << "}"; +} + +// PairOfRange is treated as columns. In text mode, put a space between columns. +template +void deref_and_print(std::ostream &stream, const PairOfRange &arg, PrintMode) { + deref_and_print(stream, arg.l, PrintMode()); + if(PrintMode::is_text) stream << " "; + deref_and_print(stream, arg.r, PrintMode()); +} + +// VecOfRange is treated as columns. In text mode, put a space between columns. +template +void deref_and_print(std::ostream &stream, const VecOfRange &arg, PrintMode) { + if(PrintMode::is_binfmt && arg.rvec.empty()) throw plotting_empty_container(); + for(size_t i=0; i +typename std::enable_if_t<(Depth==1) && !PrintMode::is_size> +print_block(std::ostream &stream, T &arg, PrintMode) { + if(PrintMode::is_binfmt && arg.is_end()) throw plotting_empty_container(); + for(; !arg.is_end(); arg.inc()) { + //print_entry(arg.deref()); + deref_and_print(stream, arg, PrintMode()); + // If asked to print the binary format string, only the first element needs to be + // looked at. + if(PrintMode::is_binfmt) break; + if(PrintMode::is_text) stream << std::endl; + } +} + +// Depth>1 and we are not asked to print the size of the array. Loop over the range and +// recurse into print_block() with Depth -> Depth-1. +template +typename std::enable_if_t<(Depth>1) && !PrintMode::is_size> +print_block(std::ostream &stream, T &arg, PrintMode) { + if(PrintMode::is_binfmt && arg.is_end()) throw plotting_empty_container(); + bool first = true; + for(; !arg.is_end(); arg.inc()) { + if(first) { + first = false; + } else { + if(PrintMode::is_text) stream << std::endl; + } + if(debug_array_print && PrintMode::is_text) stream << "" << std::endl; + if(arg.is_end()) throw plotting_empty_container(); + typename T::subiter_type sub = arg.deref_subiter(); + print_block(stream, sub, PrintMode()); + // If asked to print the binary format string, only the first element needs to be + // looked at. + if(PrintMode::is_binfmt) break; + } +} + +// Determine how many elements are in the given range. Used in the functions below. +template +size_t get_range_size(const T &arg) { + // FIXME - not the fastest way. Implement a size() method for range. + size_t ret = 0; + for(T i=arg; !i.is_end(); i.inc()) ++ret; + return ret; +} + +// Depth==1 and we are asked to print the size of the array. +template +typename std::enable_if_t<(Depth==1) && PrintMode::is_size> +print_block(std::ostream &stream, T &arg, PrintMode) { + stream << get_range_size(arg); +} + +// Depth>1 and we are asked to print the size of the array. +template +typename std::enable_if_t<(Depth>1) && PrintMode::is_size> +print_block(std::ostream &stream, T &arg, PrintMode) { + if(arg.is_end()) throw plotting_empty_container(); + // It seems that size for two dimensional arrays needs the fastest varying index first, + // contrary to intuition. The gnuplot documentation is not too clear on this point. + typename T::subiter_type sub = arg.deref_subiter(); + print_block(stream, sub, PrintMode()); + stream << "," << get_range_size(arg); +} + +// }}}2 + +// {{{2 handle_colunwrap_tag() +// +// If passed the ColUnwrapYes then treat the outermost nested container as columns by calling +// get_columns_range(). Otherwise just call get_range(). The range iterator is then passed to +// print_block() for further processing. + +template +void handle_colunwrap_tag(std::ostream &stream, const T &arg, ColUnwrapNo, PrintMode) { + static_assert(ArrayTraits::depth >= Depth, "container not deep enough"); + typename ArrayTraits::range_type range = ArrayTraits::get_range(arg); + print_block(stream, range, PrintMode()); +} + +template +void handle_colunwrap_tag(std::ostream &stream, const T &arg, ColUnwrapYes, PrintMode) { + static_assert(ArrayTraits::depth >= Depth+1, "container not deep enough"); + VecOfRange::range_type::subiter_type> cols = get_columns_range(arg); + print_block(stream, cols, PrintMode()); +} + +// }}}2 + +// {{{2 handle_organization_tag() +// +// Parse the OrganizationMode tag then forward to handle_colunwrap_tag() for further +// processing. If passed the Mode1D or Mode2D tags, then set Depth=1 or Depth=2. If passed +// Mode{1,2}DUnwrap then use the ColUnwrapYes tag. If passed ModeAuto (which is for legacy +// support) then use ModeAutoDecoder to guess which of Mode1D, Mode2D, etc. should be used. + +template +void handle_organization_tag(std::ostream &stream, const T &arg, Mode1D, PrintMode) { + handle_colunwrap_tag<1>(stream, arg, ColUnwrapNo(), PrintMode()); +} + +template +void handle_organization_tag(std::ostream &stream, const T &arg, Mode2D, PrintMode) { + handle_colunwrap_tag<2>(stream, arg, ColUnwrapNo(), PrintMode()); +} + +template +void handle_organization_tag(std::ostream &stream, const T &arg, Mode1DUnwrap, PrintMode) { + handle_colunwrap_tag<1>(stream, arg, ColUnwrapYes(), PrintMode()); +} + +template +void handle_organization_tag(std::ostream &stream, const T &arg, Mode2DUnwrap, PrintMode) { + handle_colunwrap_tag<2>(stream, arg, ColUnwrapYes(), PrintMode()); +} + +template +void handle_organization_tag(std::ostream &stream, const T &arg, ModeAuto, PrintMode) { + handle_organization_tag(stream, arg, typename ModeAutoDecoder::mode(), PrintMode()); +} + +// }}}2 + +// The entry point for the processing defined in this section. It just forwards immediately to +// handle_organization_tag(). This function is only here to give a sane name to the entry +// point. +// +// The allowed values for the OrganizationMode and PrintMode tags are defined in the beginning +// of this section. +template +void top_level_array_sender(std::ostream &stream, const T &arg, OrganizationMode, PrintMode) { + handle_organization_tag(stream, arg, OrganizationMode(), PrintMode()); +} + +// }}}1 + +// {{{1 PlotGroup + +class PlotData { +public: + PlotData() { } + + template + PlotData( + const T &arg, + const std::string &_plotspec, + const std::string &_arr_or_rec, + OrganizationMode, PrintMode + ) : + plotspec(_plotspec), + is_text(PrintMode::is_text), + is_inline(true), + has_data(true), + arr_or_rec(_arr_or_rec) + { + { + std::ostringstream tmp; + top_level_array_sender(tmp, arg, OrganizationMode(), PrintMode()); + data = tmp.str(); + } + + if(!is_text) { + try { + { + std::ostringstream tmp; + top_level_array_sender(tmp, arg, OrganizationMode(), ModeBinfmt()); + bin_fmt = tmp.str(); + } + { + std::ostringstream tmp; + top_level_array_sender(tmp, arg, OrganizationMode(), ModeSize()); + bin_size = tmp.str(); + } + } catch(const plotting_empty_container &) { + bin_fmt = ""; + bin_size = "0"; + } + } + } + + explicit PlotData(const std::string &_plotspec) : + plotspec(_plotspec), + is_text(true), + is_inline(false), + has_data(false) + { } + + PlotData &file(const std::string &fn) { + filename = fn; + is_inline = false; + + std::ios_base::openmode mode = std::fstream::out; + if(!is_text) mode |= std::fstream::binary; + std::fstream fh(filename.c_str(), mode); + fh << data; + fh.close(); + + return *this; + } + + std::string plotCmd() const { + std::string cmd; + if(has_data) { + if(filename.empty()) { + cmd += "'-' "; + } else { + // FIXME - hopefully filename doesn't contain quotes or such... + cmd += "'" + filename + "' "; + } + if(!is_text) { + cmd += binConfig() + " "; + } + } + cmd += plotspec; + return cmd; + } + + bool isInline() const { + return is_inline; + } + + const std::string &getData() const { + return data; + } + + bool isText() const { return is_text; } + + bool isBinary() const { return !is_text; } + +private: + std::string binConfig() const { + return "binary format='" + bin_fmt + "' " + arr_or_rec + "=(" + bin_size + ")"; + } + +private: + std::string plotspec; + bool is_text; + bool is_inline; + bool has_data; + std::string data; + std::string filename; + std::string arr_or_rec; + std::string bin_fmt; + std::string bin_size; +}; + +class PlotGroup { +public: + friend class Gnuplot; + + explicit PlotGroup(const std::string &plot_type_) : plot_type(plot_type_) { } + + PlotGroup &add_preamble(const std::string &s) { + preamble_lines.push_back(s); + return *this; + } + + PlotGroup &add_plot(const std::string &plotspec) { plots.emplace_back(plotspec); return *this; } + + template PlotGroup &add_plot1d (const T &arg, const std::string &plotspec="", const std::string &text_array_record="text") { add(arg, plotspec, text_array_record, Mode1D ()); return *this; } + template PlotGroup &add_plot2d (const T &arg, const std::string &plotspec="", const std::string &text_array_record="text") { add(arg, plotspec, text_array_record, Mode2D ()); return *this; } + template PlotGroup &add_plot1d_colmajor(const T &arg, const std::string &plotspec="", const std::string &text_array_record="text") { add(arg, plotspec, text_array_record, Mode1DUnwrap()); return *this; } + template PlotGroup &add_plot2d_colmajor(const T &arg, const std::string &plotspec="", const std::string &text_array_record="text") { add(arg, plotspec, text_array_record, Mode2DUnwrap()); return *this; } + + PlotGroup &file(const std::string &fn) { + assert(!plots.empty()); + plots.back().file(fn); + return *this; + } + + size_t num_plots() const { return plots.size(); } + +private: + template + void add(const T &arg, const std::string &plotspec, const std::string &text_array_record, OrganizationMode) { + if(!( + text_array_record == "text" || + text_array_record == "array" || + text_array_record == "record" + )) throw std::logic_error("text_array_record must be one of text, array, or record (was "+ + text_array_record+")"); + + if(text_array_record == "text") { + plots.emplace_back(arg, plotspec, + "array", // arbitrary value + OrganizationMode(), ModeText()); + } else { + plots.emplace_back(arg, plotspec, text_array_record, + OrganizationMode(), ModeBinary()); + } + } + + std::string plot_type; + std::vector preamble_lines; + std::vector plots; +}; + +// }}}1 + +// {{{1 FileHandleWrapper + +// This holds the file handle that gnuplot commands will be sent to. The purpose of this +// wrapper is twofold: +// 1. It allows storing the FILE* before it gets passed to the boost::iostreams::stream +// constructor (which is a base class of the main Gnuplot class). This is accomplished +// via multiple inheritance as described at http://stackoverflow.com/a/3821756/1048959 +// 2. It remembers whether the handle needs to be closed via fclose or pclose. +struct FileHandleWrapper { + FileHandleWrapper(std::FILE *_fh, bool _should_use_pclose) : + wrapped_fh(_fh), should_use_pclose(_should_use_pclose) { } + + void fh_close() { + if(should_use_pclose) { + if(GNUPLOT_PCLOSE(wrapped_fh)) { + std::cerr << "pclose returned error: " << strerror(errno) << std::endl; + } + } else { + if(fclose(wrapped_fh)) { + std::cerr << "fclose returned error" << std::endl; + } + } + } + + int fh_fileno() { + return GNUPLOT_FILENO(wrapped_fh); + } + + std::FILE *wrapped_fh; + bool should_use_pclose; +}; + +// }}}1 + +// {{{1 Main class + +class Gnuplot : + // Some setup needs to be done before obtaining the file descriptor that gets passed to + // boost::iostreams::stream. This is accomplished by using a multiple inheritance trick, + // as described at http://stackoverflow.com/a/3821756/1048959 + private FileHandleWrapper, + public boost::iostreams::stream +{ +private: + static std::string get_default_cmd() { + GNUPLOT_MSVC_WARNING_4996_PUSH + char *from_env = std::getenv("GNUPLOT_IOSTREAM_CMD"); + GNUPLOT_MSVC_WARNING_4996_POP + if(from_env && from_env[0]) { + return from_env; + } else { + return GNUPLOT_DEFAULT_COMMAND; + } + } + + static FileHandleWrapper open_cmdline(const std::string &in) { + std::string cmd = in.empty() ? get_default_cmd() : in; + assert(!cmd.empty()); + if(cmd[0] == '>') { + std::string fn = cmd.substr(1); + GNUPLOT_MSVC_WARNING_4996_PUSH + FILE *fh = std::fopen(fn.c_str(), "w"); + GNUPLOT_MSVC_WARNING_4996_POP + if(!fh) throw std::ios_base::failure("cannot open file "+fn); + return FileHandleWrapper(fh, false); + } else { + FILE *fh = GNUPLOT_POPEN(cmd.c_str(), "w"); + if(!fh) throw std::ios_base::failure("cannot open pipe "+cmd); + return FileHandleWrapper(fh, true); + } + } + +public: + explicit Gnuplot(const std::string &_cmd="") : + FileHandleWrapper(open_cmdline(_cmd)), + boost::iostreams::stream( + fh_fileno(), +#if BOOST_VERSION >= 104400 + boost::iostreams::never_close_handle +#else + false +#endif + ), + feedback(nullptr), + tmp_files(new GnuplotTmpfileCollection()), + debug_messages(false), + transport_tmpfile(false) + { + set_stream_options(*this); + } + + explicit Gnuplot(FILE *_fh) : + FileHandleWrapper(_fh, 0), + boost::iostreams::stream( + fh_fileno(), +#if BOOST_VERSION >= 104400 + boost::iostreams::never_close_handle +#else + false +#endif + ), + feedback(nullptr), + tmp_files(new GnuplotTmpfileCollection()), + debug_messages(false), + transport_tmpfile(false) + { + set_stream_options(*this); + } + +private: + // noncopyable + Gnuplot(const Gnuplot &) = delete; + const Gnuplot& operator=(const Gnuplot &) = delete; + +public: + ~Gnuplot() { + if(debug_messages) { + std::cerr << "ending gnuplot session" << std::endl; + } + + // FIXME - boost's close method calls close() on the file descriptor, but we need to + // use sometimes use pclose instead. For now, just skip calling boost's close and use + // flush just in case. + do_flush(); + // Wish boost had a pclose method... + //close(); + + fh_close(); + + delete feedback; + } + + void useTmpFile(bool state) { + transport_tmpfile = state; + } + + void clearTmpfiles() { + // destructors will cause deletion + tmp_files->clear(); + } + +public: + void do_flush() { + *this << std::flush; + fflush(wrapped_fh); + } + +private: + std::string make_tmpfile() { + return tmp_files->make_tmpfile(); + } + + void set_stream_options(std::ostream &os) const + { + os << std::defaultfloat << std::setprecision(17); // refer + } + +public: +// {{{2 Generic sender routines. +// +// These are declared public, but are undocumented. It is recommended to use the functions in +// the next section, which serve as adapters that pass specific values for the OrganizationMode +// tag. + + template + Gnuplot &send(const T &arg, OrganizationMode) { + top_level_array_sender(*this, arg, OrganizationMode(), ModeText()); + *this << "e" << std::endl; // gnuplot's "end of array" token + do_flush(); // probably not really needed, but doesn't hurt + return *this; + } + + template + Gnuplot &sendBinary(const T &arg, OrganizationMode) { + top_level_array_sender(*this, arg, OrganizationMode(), ModeBinary()); + do_flush(); // probably not really needed, but doesn't hurt + return *this; + } + + template + std::string binfmt(const T &arg, const std::string &arr_or_rec, OrganizationMode) { + assert((arr_or_rec == "array") || (arr_or_rec == "record")); + std::string ret; + try { + std::ostringstream tmp; + tmp << " format='"; + top_level_array_sender(tmp, arg, OrganizationMode(), ModeBinfmt()); + tmp << "' " << arr_or_rec << "=("; + top_level_array_sender(tmp, arg, OrganizationMode(), ModeSize()); + tmp << ")"; + tmp << " "; + ret = tmp.str(); + } catch(const plotting_empty_container &) { + ret = std::string(" format='' ") + arr_or_rec + "=(0) "; + } + return ret; + } + + // NOTE: empty filename makes temporary file + template + std::string file(const T &arg, std::string filename, OrganizationMode) { + if(filename.empty()) filename = make_tmpfile(); + std::fstream tmp_stream(filename.c_str(), std::fstream::out); + tmp_stream.copyfmt(*this); + top_level_array_sender(tmp_stream, arg, OrganizationMode(), ModeText()); + tmp_stream.close(); + + std::ostringstream cmdline; + // FIXME - hopefully filename doesn't contain quotes or such... + cmdline << " '" << filename << "' "; + return cmdline.str(); + } + + // NOTE: empty filename makes temporary file + template + std::string binaryFile(const T &arg, std::string filename, const std::string &arr_or_rec, OrganizationMode) { + if(filename.empty()) filename = make_tmpfile(); + std::fstream tmp_stream(filename.c_str(), std::fstream::out | std::fstream::binary); + top_level_array_sender(tmp_stream, arg, OrganizationMode(), ModeBinary()); + tmp_stream.close(); + + std::ostringstream cmdline; + // FIXME - hopefully filename doesn't contain quotes or such... + cmdline << " '" << filename << "' binary" << binfmt(arg, arr_or_rec, OrganizationMode()); + return cmdline.str(); + } + +// }}}2 + +// {{{2 Deprecated data sending interface that guesses an appropriate OrganizationMode. This is here +// for reverse compatibility. Don't use it. A warning will be printed if +// GNUPLOT_DEPRECATE_WARN is defined. + + template Gnuplot GNUPLOT_DEPRECATE("use send1d or send2d") + &send(const T &arg) { return send(arg, ModeAuto()); } + + template std::string GNUPLOT_DEPRECATE("use binfmt1d or binfmt2d") + binfmt(const T &arg, const std::string &arr_or_rec="array") + { return binfmt(arg, arr_or_rec, ModeAuto()); } + + template Gnuplot GNUPLOT_DEPRECATE("use sendBinary1d or sendBinary2d") + &sendBinary(const T &arg) { return sendBinary(arg, ModeAuto()); } + + template std::string GNUPLOT_DEPRECATE("use file1d or file2d") + file(const T &arg, const std::string &filename="") + { return file(arg, filename, ModeAuto()); } + + template std::string GNUPLOT_DEPRECATE("use binArr1d or binArr2d") + binaryFile(const T &arg, const std::string &filename="", const std::string &arr_or_rec="array") + { return binaryFile(arg, filename, arr_or_rec, ModeAuto()); } + +// }}}2 + +// {{{2 Public (documented) data sending interface. +// +// It seems odd to define 16 different functions, but I think this ends up being the most +// convenient in terms of usage by the end user. + + template Gnuplot &send1d (const T &arg) { return send(arg, Mode1D ()); } + template Gnuplot &send2d (const T &arg) { return send(arg, Mode2D ()); } + template Gnuplot &send1d_colmajor(const T &arg) { return send(arg, Mode1DUnwrap()); } + template Gnuplot &send2d_colmajor(const T &arg) { return send(arg, Mode2DUnwrap()); } + + template Gnuplot &sendBinary1d (const T &arg) { return sendBinary(arg, Mode1D ()); } + template Gnuplot &sendBinary2d (const T &arg) { return sendBinary(arg, Mode2D ()); } + template Gnuplot &sendBinary1d_colmajor(const T &arg) { return sendBinary(arg, Mode1DUnwrap()); } + template Gnuplot &sendBinary2d_colmajor(const T &arg) { return sendBinary(arg, Mode2DUnwrap()); } + + template std::string file1d (const T &arg, const std::string &filename="") { return file(arg, filename, Mode1D ()); } + template std::string file2d (const T &arg, const std::string &filename="") { return file(arg, filename, Mode2D ()); } + template std::string file1d_colmajor(const T &arg, const std::string &filename="") { return file(arg, filename, Mode1DUnwrap()); } + template std::string file2d_colmajor(const T &arg, const std::string &filename="") { return file(arg, filename, Mode2DUnwrap()); } + + template std::string binFmt1d (const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode1D ()); } + template std::string binFmt2d (const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode2D ()); } + template std::string binFmt1d_colmajor(const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode1DUnwrap()); } + template std::string binFmt2d_colmajor(const T &arg, const std::string &arr_or_rec) { return binfmt(arg, arr_or_rec, Mode2DUnwrap()); } + + template std::string binFile1d (const T &arg, const std::string &arr_or_rec, const std::string &filename="") { return binaryFile(arg, filename, arr_or_rec, Mode1D ()); } + template std::string binFile2d (const T &arg, const std::string &arr_or_rec, const std::string &filename="") { return binaryFile(arg, filename, arr_or_rec, Mode2D ()); } + template 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()); } + template 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()); } + +// }}}2 + +#ifdef GNUPLOT_ENABLE_FEEDBACK +public: + // Input variables are set to the mouse position and button. If the gnuplot + // window is closed, button -1 is returned. The msg parameter is the prompt + // that is printed to the console. + void getMouse( + double &mx, double &my, int &mb, + std::string msg="Click Mouse!" + ) { + allocFeedback(); + + *this << "set mouse" << std::endl; + *this << "pause mouse \"" << msg << "\\n\"" << std::endl; + *this << "if (exists(\"MOUSE_X\")) print MOUSE_X, MOUSE_Y, MOUSE_BUTTON; else print 0, 0, -1;" << std::endl; + if(debug_messages) { + std::cerr << "begin scanf" << std::endl; + } + if(3 != fscanf(feedback->handle(), "%50lf %50lf %50d", &mx, &my, &mb)) { + throw std::runtime_error("could not parse reply"); + } + if(debug_messages) { + std::cerr << "end scanf" << std::endl; + } + } + +private: + void allocFeedback() { + if(!feedback) { +#ifdef GNUPLOT_ENABLE_PTY + feedback = new GnuplotFeedbackPty(debug_messages); +//#elif defined GNUPLOT_USE_TMPFILE +//// Currently this doesn't work since fscanf doesn't block (need something like "tail -f") +// feedback = new GnuplotFeedbackTmpfile(debug_messages); +#else + // This shouldn't happen because we are in an `#ifdef GNUPLOT_ENABLE_FEEDBACK` + // block which should only be activated if GNUPLOT_ENABLE_PTY is defined. + static_assert((sizeof(T) == 0), "No feedback mechanism defined."); +#endif + *this << "set print \"" << feedback->filename() << "\"" << std::endl; + } + } +#endif // GNUPLOT_ENABLE_FEEDBACK + +// {{{2 PlotGroup + +public: + static PlotGroup plotGroup() { + return PlotGroup("plot"); + } + + static PlotGroup splotGroup() { + return PlotGroup("splot"); + } + + Gnuplot &send(const PlotGroup &plot_group) { + return send(PlotGroup(plot_group)); + } + + Gnuplot &send(const PlotGroup &&plot_group) { + for(const std::string &s : plot_group.preamble_lines) { + *this << s << "\n"; + } + + std::vector spl = std::move(plot_group.plots); + + if(transport_tmpfile) { + for(size_t i=0; i tmp_files; +public: + bool debug_messages; + bool transport_tmpfile; +}; + +inline Gnuplot &operator<<(Gnuplot &gp, PlotGroup &sp) { + return gp.send(sp); +} + +inline Gnuplot &operator<<(Gnuplot &gp, PlotGroup &&sp) { + return gp.send(sp); +} + +// }}}1 + +} // namespace gnuplotio + +// The first version of this library didn't use namespaces, and now this must be here forever +// for reverse compatibility. +using gnuplotio::Gnuplot; + +#endif // GNUPLOT_IOSTREAM_H + +// {{{1 Support for 3rd party array libraries + +// {{{2 Blitz support + +// This is outside of the main header guard so that it will be compiled when people do +// something like this: +// #include "gnuplot-iostream.h" +// #include +// #include "gnuplot-iostream.h" +// Note that it has its own header guard to avoid double inclusion. + +#ifdef BZ_BLITZ_H +#ifndef GNUPLOT_BLITZ_SUPPORT_LOADED +#define GNUPLOT_BLITZ_SUPPORT_LOADED +namespace gnuplotio { + +template +struct BinfmtSender> { + static void send(std::ostream &stream) { + for(int i=0; i::send(stream); + } + } +}; + +template +struct TextSender> { + static void send(std::ostream &stream, const blitz::TinyVector &v) { + for(int i=0; i::send(stream, v[i]); + } + } +}; + +template +struct BinarySender> { + static void send(std::ostream &stream, const blitz::TinyVector &v) { + for(int i=0; i::send(stream, v[i]); + } + } +}; + +class Error_WasBlitzPartialSlice { }; + +template +class BlitzIterator { +public: + BlitzIterator() : p(nullptr) { } + BlitzIterator( + const blitz::Array *_p, + const blitz::TinyVector _idx + ) : p(_p), idx(_idx) { } + + typedef Error_WasBlitzPartialSlice value_type; + typedef BlitzIterator subiter_type; + static constexpr bool is_container = true; + + // FIXME - it would be nice to also handle one-based arrays + bool is_end() const { + return idx[ArrayDim-SliceDim] == p->shape()[ArrayDim-SliceDim]; + } + + void inc() { + ++idx[ArrayDim-SliceDim]; + } + + value_type deref() const { + static_assert((sizeof(T) == 0), "cannot deref a blitz slice"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + subiter_type deref_subiter() const { + return BlitzIterator(p, idx); + } + +private: + const blitz::Array *p; + blitz::TinyVector idx; +}; + +template +class BlitzIterator { +public: + BlitzIterator() : p(nullptr) { } + BlitzIterator( + const blitz::Array *_p, + const blitz::TinyVector _idx + ) : p(_p), idx(_idx) { } + + typedef T value_type; + typedef Error_WasNotContainer subiter_type; + static constexpr bool is_container = false; + + // FIXME - it would be nice to also handle one-based arrays + bool is_end() const { + return idx[ArrayDim-1] == p->shape()[ArrayDim-1]; + } + + void inc() { + ++idx[ArrayDim-1]; + } + + value_type deref() const { + return (*p)(idx); + } + + subiter_type deref_subiter() const { + static_assert((sizeof(T) == 0), "argument was not a container"); + throw std::logic_error("static assert should have been triggered by this point"); + } + +private: + const blitz::Array *p; + blitz::TinyVector idx; +}; + +template +class ArrayTraits> : public ArrayTraitsDefaults { +public: + static constexpr bool allow_auto_unwrap = false; + static constexpr size_t depth = ArrayTraits::depth + ArrayDim; + + typedef BlitzIterator range_type; + + static range_type get_range(const blitz::Array &arg) { + blitz::TinyVector start_idx; + start_idx = 0; + return range_type(&arg, start_idx); + } +}; + +} // namespace gnuplotio +#endif // GNUPLOT_BLITZ_SUPPORT_LOADED +#endif // BZ_BLITZ_H + +// }}}2 + +// {{{2 Armadillo support + +// This is outside of the main header guard so that it will be compiled when people do +// something like this: +// #include "gnuplot-iostream.h" +// #include +// #include "gnuplot-iostream.h" +// Note that it has its own header guard to avoid double inclusion. + +#ifdef ARMA_INCLUDES +#ifndef GNUPLOT_ARMADILLO_SUPPORT_LOADED +#define GNUPLOT_ARMADILLO_SUPPORT_LOADED +namespace gnuplotio { + +template static constexpr bool dont_treat_as_stl_container> = true; +template static constexpr bool dont_treat_as_stl_container> = true; +template static constexpr bool dont_treat_as_stl_container> = true; +template static constexpr bool dont_treat_as_stl_container> = true; +template static constexpr bool dont_treat_as_stl_container> = true; + +// {{{3 Cube + +template +class ArrayTraits> : public ArrayTraitsDefaults { + class SliceRange { + public: + SliceRange() : p(nullptr), col(0), slice(0) { } + explicit SliceRange(const arma::Cube *_p, size_t _row, size_t _col) : + p(_p), row(_row), col(_col), slice(0) { } + + typedef T value_type; + typedef Error_WasNotContainer subiter_type; + static constexpr bool is_container = false; + + bool is_end() const { return slice == p->n_slices; } + + void inc() { ++slice; } + + value_type deref() const { + return (*p)(row, col, slice); + } + + subiter_type deref_subiter() const { + static_assert((sizeof(T) == 0), "argument was not a container"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + private: + const arma::Cube *p; + size_t row, col, slice; + }; + + class ColRange { + public: + ColRange() : p(nullptr), row(0), col(0) { } + explicit ColRange(const arma::Cube *_p, size_t _row) : + p(_p), row(_row), col(0) { } + + typedef T value_type; + typedef SliceRange subiter_type; + static constexpr bool is_container = true; + + bool is_end() const { return col == p->n_cols; } + + void inc() { ++col; } + + value_type deref() const { + static_assert((sizeof(T) == 0), "can't call deref on an armadillo cube col"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + subiter_type deref_subiter() const { + return subiter_type(p, row, col); + } + + private: + const arma::Cube *p; + size_t row, col; + }; + + class RowRange { + public: + RowRange() : p(nullptr), row(0) { } + explicit RowRange(const arma::Cube *_p) : p(_p), row(0) { } + + typedef T value_type; + typedef ColRange subiter_type; + static constexpr bool is_container = true; + + bool is_end() const { return row == p->n_rows; } + + void inc() { ++row; } + + value_type deref() const { + static_assert((sizeof(T) == 0), "can't call deref on an armadillo cube row"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + subiter_type deref_subiter() const { + return subiter_type(p, row); + } + + private: + const arma::Cube *p; + size_t row; + }; + +public: + static constexpr bool allow_auto_unwrap = false; + static constexpr size_t depth = ArrayTraits::depth + 3; + + typedef RowRange range_type; + + static range_type get_range(const arma::Cube &arg) { + //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl; + return range_type(&arg); + } +}; + +// }}}3 + +// {{{3 Mat and Field + +template +class ArrayTraits_ArmaMatOrField : public ArrayTraitsDefaults { + class ColRange { + public: + ColRange() : p(nullptr), row(0), col(0) { } + explicit ColRange(const RF *_p, size_t _row) : + p(_p), row(_row), col(0) { } + + typedef T value_type; + typedef Error_WasNotContainer subiter_type; + static constexpr bool is_container = false; + + bool is_end() const { return col == p->n_cols; } + + void inc() { ++col; } + + value_type deref() const { + return (*p)(row, col); + } + + subiter_type deref_subiter() const { + static_assert((sizeof(T) == 0), "argument was not a container"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + private: + const RF *p; + size_t row, col; + }; + + class RowRange { + public: + RowRange() : p(nullptr), row(0) { } + explicit RowRange(const RF *_p) : p(_p), row(0) { } + + typedef T value_type; + typedef ColRange subiter_type; + static constexpr bool is_container = true; + + bool is_end() const { return row == p->n_rows; } + + void inc() { ++row; } + + value_type deref() const { + static_assert((sizeof(T) == 0), "can't call deref on an armadillo matrix row"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + subiter_type deref_subiter() const { + return subiter_type(p, row); + } + + private: + const RF *p; + size_t row; + }; + +public: + static constexpr bool allow_auto_unwrap = false; + static constexpr size_t depth = ArrayTraits::depth + 2; + + typedef RowRange range_type; + + static range_type get_range(const RF &arg) { + //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl; + return range_type(&arg); + } +}; + +template +class ArrayTraits> : public ArrayTraits_ArmaMatOrField, T> { }; + +template +class ArrayTraits> : public ArrayTraits_ArmaMatOrField, T> { }; + +// }}}3 + +// {{{3 Row + +template +class ArrayTraits> : public ArrayTraitsDefaults { +public: + static constexpr bool allow_auto_unwrap = false; + + typedef IteratorRange::const_iterator, T> range_type; + + static range_type get_range(const arma::Row &arg) { + //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl; + return range_type(arg.begin(), arg.end()); + } +}; + +// }}}3 + +// {{{3 Col + +template +class ArrayTraits> : public ArrayTraitsDefaults { +public: + static constexpr bool allow_auto_unwrap = false; + + typedef IteratorRange::const_iterator, T> range_type; + + static range_type get_range(const arma::Col &arg) { + //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl; + return range_type(arg.begin(), arg.end()); + } +}; + +// }}}3 + +} // namespace gnuplotio +#endif // GNUPLOT_ARMADILLO_SUPPORT_LOADED +#endif // ARMA_INCLUDES + +// }}}2 + +// {{{2 Eigen support + +// This is outside of the main header guard so that it will be compiled when people do +// something like this: +// #include "gnuplot-iostream.h" +// #include +// #include "gnuplot-iostream.h" +// Note that it has its own header guard to avoid double inclusion. + +#ifdef EIGEN_CORE_H +#ifndef GNUPLOT_EIGEN_SUPPORT_LOADED +#define GNUPLOT_EIGEN_SUPPORT_LOADED +namespace gnuplotio { + +template +static constexpr bool is_eigen_matrix = false; + +template +static constexpr bool is_eigen_matrix, T>>> = true; + +static_assert( is_eigen_matrix); +static_assert(!is_eigen_matrix); + +template +static constexpr bool dont_treat_as_stl_container>> = true; + +static_assert(dont_treat_as_stl_container); + +// {{{3 Matrix + +template +class ArrayTraits_Eigen1D : public ArrayTraitsDefaults { + class IdxRange { + public: + IdxRange() : p(nullptr), idx(0) { } + explicit IdxRange(const RF *_p) : + p(_p), idx(0) { } + + using value_type = typename RF::value_type; + typedef Error_WasNotContainer subiter_type; + static constexpr bool is_container = false; + + bool is_end() const { return idx == p->size(); } + + void inc() { ++idx; } + + value_type deref() const { + return (*p)(idx); + } + + subiter_type deref_subiter() const { + static_assert((sizeof(value_type) == 0), "argument was not a container"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + private: + const RF *p; + Eigen::Index idx; + }; + +public: + static constexpr bool allow_auto_unwrap = false; + static constexpr size_t depth = ArrayTraits::depth + 1; + + typedef IdxRange range_type; + + static range_type get_range(const RF &arg) { + //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl; + return range_type(&arg); + } +}; + +template +class ArrayTraits_Eigen2D : public ArrayTraitsDefaults { + class ColRange { + public: + ColRange() : p(nullptr), row(0), col(0) { } + explicit ColRange(const RF *_p, Eigen::Index _row) : + p(_p), row(_row), col(0) { } + + using value_type = typename RF::value_type; + typedef Error_WasNotContainer subiter_type; + static constexpr bool is_container = false; + + bool is_end() const { return col == p->cols(); } + + void inc() { ++col; } + + value_type deref() const { + return (*p)(row, col); + } + + subiter_type deref_subiter() const { + static_assert((sizeof(value_type) == 0), "argument was not a container"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + private: + const RF *p; + Eigen::Index row, col; + }; + + class RowRange { + public: + RowRange() : p(nullptr), row(0) { } + explicit RowRange(const RF *_p) : p(_p), row(0) { } + + using value_type = typename RF::value_type; + typedef ColRange subiter_type; + static constexpr bool is_container = true; + + bool is_end() const { return row == p->rows(); } + + void inc() { ++row; } + + value_type deref() const { + static_assert((sizeof(value_type) == 0), "can't call deref on an eigen matrix row"); + throw std::logic_error("static assert should have been triggered by this point"); + } + + subiter_type deref_subiter() const { + return subiter_type(p, row); + } + + private: + const RF *p; + Eigen::Index row; + }; + +public: + static constexpr bool allow_auto_unwrap = false; + static constexpr size_t depth = ArrayTraits::depth + 2; + + typedef RowRange range_type; + + static range_type get_range(const RF &arg) { + //std::cout << arg.n_elem << "," << arg.n_rows << "," << arg.n_cols << std::endl; + return range_type(&arg); + } +}; + +template +class ArrayTraits>> : + public std::conditional_t< + T::RowsAtCompileTime == 1 || T::ColsAtCompileTime == 1, + ArrayTraits_Eigen1D, + ArrayTraits_Eigen2D + > { }; + +// }}}3 + +} // namespace gnuplotio +#endif // GNUPLOT_EIGEN_SUPPORT_LOADED +#endif // EIGEN_CORE_H + +// }}}2 + +// }}}1 \ No newline at end of file