20#include "../core/xexpression.hpp"
21#include "../core/xmath.hpp"
22#include "../views/xstrided_view.hpp"
34 namespace print_options
56 inline void set_line_width(
int line_width)
58 print_options().line_width = line_width;
67 inline void set_threshold(
int threshold)
69 print_options().threshold = threshold;
94#define DEFINE_LOCAL_PRINT_OPTION(NAME) \
106 static int id = std::ios_base::xalloc(); \
119 inline std::ostream& operator<<(std::ostream& out, const NAME& n) \
121 out.iword(NAME::id()) = n.value(); \
137 DEFINE_LOCAL_PRINT_OPTION(line_width)
151 DEFINE_LOCAL_PRINT_OPTION(threshold)
165 DEFINE_LOCAL_PRINT_OPTION(edge_items)
179 DEFINE_LOCAL_PRINT_OPTION(precision)
188 template <
class E,
class F>
189 std::ostream& xoutput(
195 std::streamsize element_width,
196 std::size_t edgeitems,
200 using size_type =
typename E::size_type;
203 if (
view.dimension() == 0)
205 printer.print_next(out);
209 std::string indents(blanks,
' ');
212 size_type elems_on_line = 0;
213 const size_type ewp2 =
static_cast<size_type
>(element_width) + size_type(2);
214 const size_type line_lim =
static_cast<size_type
>(std::floor(
line_width / ewp2));
217 for (; i != size_type(
view.shape()[0] - 1); ++i)
219 if (edgeitems && size_type(
view.shape()[0]) > (edgeitems * 2) && i == edgeitems)
221 if (
view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim)
225 else if (
view.dimension() > 1)
228 out <<
"...," << std::endl << indents;
234 i = size_type(
view.shape()[0]) - edgeitems;
236 if (
view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim)
238 out << std::endl << indents;
241 slices.push_back(
static_cast<int>(i));
242 xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems,
line_width) <<
',';
246 if ((
view.dimension() == 1) && !(line_lim != 0 && elems_on_line >= line_lim))
250 else if (
view.dimension() > 1)
252 out << std::endl << indents;
255 if (
view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim)
257 out << std::endl << indents;
259 slices.push_back(
static_cast<int>(i));
260 xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems,
line_width) <<
'}';
266 template <
class F,
class E>
269 using size_type =
typename E::size_type;
271 if (
view.dimension() == 0)
278 for (; i !=
static_cast<size_type
>(
view.shape()[0] - 1); ++i)
280 if (lim && size_type(
view.shape()[0]) > (lim * 2) && i == lim)
282 i =
static_cast<size_type
>(
view.shape()[0]) - lim;
284 slices.push_back(
static_cast<int>(i));
285 recurser_run(fn, e, slices, lim);
288 slices.push_back(
static_cast<int>(i));
289 recurser_run(fn, e, slices, lim);
294 template <
class T,
class E =
void>
298 struct printer<T, std::enable_if_t<std::is_floating_point<typename T::value_type>::value>>
300 using value_type = std::decay_t<typename T::value_type>;
301 using cache_type = std::vector<value_type>;
302 using cache_iterator =
typename cache_type::const_iterator;
304 explicit printer(std::streamsize precision)
305 : m_precision(precision)
311 m_precision = m_required_precision < m_precision ? m_required_precision : m_precision;
312 m_it = m_cache.cbegin();
316 m_width = m_precision + 7;
317 if (m_large_exponent)
325 std::streamsize decimals = 1;
326 if (std::floor(m_max) != 0)
328 decimals += std::streamsize(std::log10(std::floor(m_max)));
331 m_width = 2 + decimals + m_precision;
333 if (!m_required_precision)
339 std::ostream& print_next(std::ostream& out)
343 std::stringstream buf;
346 buf.precision(m_precision);
348 if (!m_required_precision && !std::isinf(*m_it) && !std::isnan(*m_it))
352 std::string res = buf.str();
353 auto sit = res.rbegin();
363 if (!m_large_exponent)
365 out << std::scientific;
371 std::stringstream buf;
373 buf << std::scientific;
374 buf.precision(m_precision);
376 std::string res = buf.str();
378 if (res[res.size() - 4] ==
'e')
381 res.insert(res.size() - 2,
"0");
390 void update(
const value_type& val)
392 if (val != 0 && !std::isinf(val) && !std::isnan(val))
394 if (!m_scientific || !m_large_exponent)
396 int exponent = 1 + int(std::log10(math::abs(val)));
397 if (exponent <= -5 || exponent > 7)
400 m_required_precision = m_precision;
401 if (exponent <= -100 || exponent >= 100)
403 m_large_exponent =
true;
407 if (math::abs(val) > m_max)
409 m_max = math::abs(val);
411 if (m_required_precision < m_precision)
413 while (std::floor(val * std::pow(10, m_required_precision))
414 != val * std::pow(10, m_required_precision))
416 m_required_precision++;
420 m_cache.push_back(val);
423 std::streamsize width()
430 bool m_large_exponent =
false;
431 bool m_scientific =
false;
432 std::streamsize m_width = 9;
433 std::streamsize m_precision;
434 std::streamsize m_required_precision = 0;
435 value_type m_max = 0;
445 xtl::is_integral<typename T::value_type>::value && !std::is_same<typename T::value_type, bool>::value>>
447 using value_type = std::decay_t<typename T::value_type>;
448 using cache_type = std::vector<value_type>;
449 using cache_iterator =
typename cache_type::const_iterator;
451 explicit printer(std::streamsize)
457 m_it = m_cache.cbegin();
458 m_width = 1 + std::streamsize((m_max > 0) ? std::log10(m_max) : 0) + m_sign;
461 std::ostream& print_next(std::ostream& out)
471 void update(
const value_type& val)
473 if (math::abs(val) > m_max)
475 m_max = math::abs(val);
477 if (xtl::is_signed<value_type>::value && val < 0)
481 m_cache.push_back(val);
484 std::streamsize width()
491 std::streamsize m_width;
493 value_type m_max = 0;
500 struct printer<T, std::enable_if_t<std::is_same<typename T::value_type, bool>::value>>
502 using value_type = bool;
503 using cache_type = std::vector<bool>;
504 using cache_iterator =
typename cache_type::const_iterator;
506 explicit printer(std::streamsize)
512 m_it = m_cache.cbegin();
515 std::ostream& print_next(std::ostream& out)
531 void update(
const value_type& val)
533 m_cache.push_back(val);
536 std::streamsize width()
543 std::streamsize m_width = 5;
550 struct printer<T, std::enable_if_t<xtl::is_complex<typename T::value_type>::value>>
552 using value_type = std::decay_t<typename T::value_type>;
553 using cache_type = std::vector<bool>;
554 using cache_iterator =
typename cache_type::const_iterator;
556 explicit printer(std::streamsize precision)
557 : real_printer(precision)
558 , imag_printer(precision)
566 m_it = m_signs.cbegin();
569 std::ostream& print_next(std::ostream& out)
571 real_printer.print_next(out);
580 std::stringstream buf;
581 imag_printer.print_next(buf);
582 std::string s = buf.str();
588 std::size_t idx = s.find_last_not_of(
" ");
589 s.insert(idx + 1,
"i");
595 void update(
const value_type& val)
597 real_printer.update(val.real());
598 imag_printer.update(std::abs(val.imag()));
599 m_signs.push_back(std::signbit(val.imag()));
602 std::streamsize width()
604 return real_printer.width() + imag_printer.width() + 2;
609 printer<value_type> real_printer, imag_printer;
618 !xtl::is_fundamental<typename T::value_type>::value && !xtl::is_complex<typename T::value_type>::value>>
620 using const_reference =
typename T::const_reference;
621 using value_type = std::decay_t<typename T::value_type>;
622 using cache_type = std::vector<std::string>;
623 using cache_iterator =
typename cache_type::const_iterator;
625 explicit printer(std::streamsize)
631 m_it = m_cache.cbegin();
638 std::ostream& print_next(std::ostream& out)
646 void update(const_reference val)
648 std::stringstream buf;
650 std::string s = buf.str();
651 if (
int(s.size()) > m_width)
653 m_width = std::streamsize(s.size());
655 m_cache.push_back(s);
658 std::streamsize width()
665 std::streamsize m_width = 0;
671 struct custom_formatter
673 using value_type = std::decay_t<typename E::value_type>;
676 custom_formatter(F&& func)
681 std::string operator()(
const value_type& val)
const
688 std::function<std::string(
const value_type&)> m_func;
700 res.edge_items =
static_cast<int>(out.iword(edge_items::id()));
701 res.line_width =
static_cast<int>(out.iword(line_width::id()));
702 res.threshold =
static_cast<int>(out.iword(threshold::id()));
703 res.precision =
static_cast<int>(out.iword(precision::id()));
707 res.edge_items = print_options::print_options().edge_items;
711 out.iword(edge_items::id()) = long(0);
715 res.line_width = print_options::print_options().line_width;
719 out.iword(line_width::id()) = long(0);
723 res.threshold = print_options::print_options().threshold;
727 out.iword(threshold::id()) = long(0);
731 res.precision = print_options::print_options().precision;
735 out.iword(precision::id()) = long(0);
741 template <
class E,
class F>
742 std::ostream& pretty_print(
const xexpression<E>& e, F&& func, std::ostream& out = std::cout)
744 xfunction<detail::custom_formatter<E>, const_xclosure_t<E>> print_fun(
745 detail::custom_formatter<E>(std::forward<F>(func)),
748 return pretty_print(print_fun, out);
758 explicit fmtflags_guard(S& stream)
760 , m_flags(stream.flags())
766 m_stream.flags(m_flags);
772 std::ios_base::fmtflags m_flags;
777 std::ostream& pretty_print(
const xexpression<E>& e, std::ostream& out = std::cout)
779 detail::fmtflags_guard<std::ostream> guard(out);
781 const E& d = e.derived_cast();
784 std::size_t sz = compute_size(d.shape());
786 auto po = get_print_options(out);
788 if (sz >
static_cast<std::size_t
>(po.threshold))
790 lim =
static_cast<std::size_t
>(po.edge_items);
798 auto temp_precision = out.precision();
800 if (po.precision != -1)
802 out.precision(
static_cast<std::streamsize
>(po.precision));
803 precision =
static_cast<std::streamsize
>(po.precision);
809 detail::recurser_run(p, d, sv, lim);
812 xoutput(out, d, sv, p, 1, p.width(), lim,
static_cast<std::size_t
>(po.line_width));
814 out.precision(temp_precision);
820 inline std::ostream& operator<<(std::ostream& out,
const xexpression<E>& e)
822 return pretty_print(e, out);
829#if defined(__CLING__) || defined(__CLANG_REPL__)
io manipulator used to set the number of egde items if the summarization is triggered.
io manipulator used to set the width of the lines when printing an expression.
io manipulator used to set the precision of the floating point values when printing an expression.
io manipulator used to set the threshold after which summarization is triggered.
Base class for xexpressions.
auto operator<<(E1 &&e1, E2 &&e2) noexcept -> detail::shift_return_type_t< detail::left_shift, E1, E2 >
Bitwise left shift.
standard mathematical functions for xexpressions
std::vector< xstrided_slice< std::ptrdiff_t > > xstrided_slice_vector
vector of slices used to build a xstrided_view
auto strided_view(E &&e, S &&shape, X &&stride, std::size_t offset=0, layout_type layout=L) noexcept
Construct a strided view from an xexpression, shape, strides and offset.
auto view(E &&e, S &&... slices)
Constructs and returns a view on the specified xexpression.