diff --git a/CMakeLists.txt b/CMakeLists.txt index c942806..9f8be83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ if(ROTGEN_FORCE_DYNAMIC) src/info.cpp src/svd.cpp src/operators.cpp + src/format.cpp ) else() set ( SOURCES diff --git a/include/rotgen/common/ref.hpp b/include/rotgen/common/ref.hpp index ffde241..53503f3 100644 --- a/include/rotgen/common/ref.hpp +++ b/include/rotgen/common/ref.hpp @@ -112,7 +112,12 @@ namespace rotgen friend std::ostream& operator<<(std::ostream& os, ref const& r) { - return os << r.base() << "\n"; + return os << r.base(); + } + + friend std::ostream& operator<<(std::ostream& os, format const& r) + { + return os << format{r.matrix_.base(),r.format_}; } }; @@ -201,7 +206,12 @@ namespace rotgen friend std::ostream& operator<<(std::ostream& os, ref const& r) { - return os << r.base() << "\n"; + return os << r.base(); + } + + friend std::ostream& operator<<(std::ostream& os, format const& r) + { + return os << format{r.matrix_.base(),r.format_}; } }; diff --git a/include/rotgen/config.hpp b/include/rotgen/config.hpp index 927990a..3b17439 100644 --- a/include/rotgen/config.hpp +++ b/include/rotgen/config.hpp @@ -41,6 +41,10 @@ namespace rotgen inline constexpr int Aligned64 = 64; inline constexpr int Aligned128 = 128; inline constexpr int Aligned = default_alignment; + + inline constexpr int DontAlignCols = 1; + inline constexpr int StreamPrecision = -1; + inline constexpr int FullPrecision = -2; } namespace rotgen::detail diff --git a/include/rotgen/dynamic/format.hpp b/include/rotgen/dynamic/format.hpp new file mode 100644 index 0000000..02bfe0b --- /dev/null +++ b/include/rotgen/dynamic/format.hpp @@ -0,0 +1,51 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace rotgen +{ + class ROTGEN_EXPORT ioformat + { + private: + struct payload; + std::unique_ptr storage_; + + public: + ioformat( int precision, int flags = 0 + , std::string const& coeffSeparator = " " + , std::string const& rowSeparator = "\n" + , std::string const& rowPrefix = "", std::string const& rowSuffix = "" + , std::string const& matPrefix = "", std::string const& matSuffix = "" + , char fill = ' ' + ); + + + ~ioformat(); + + std::unique_ptr const& storage() const { return storage_; } + }; + + template + struct format + { + format(const M& m, const ioformat& f) : matrix_(m), format_(f) {} + + M const& matrix_; + ioformat const& format_; + }; + + template + std::ostream& operator<<(std::ostream& os, const format& f) + { + return os << format{f.matrix_.base(), f.format_}; + } +} diff --git a/include/rotgen/fixed/format.hpp b/include/rotgen/fixed/format.hpp new file mode 100644 index 0000000..7c2ced5 --- /dev/null +++ b/include/rotgen/fixed/format.hpp @@ -0,0 +1,34 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace rotgen +{ + using ioformat = Eigen::IOFormat; + + template + struct format + { + format(const M& m, const ioformat& f) : matrix_(m), format_(f) {} + + M const& matrix_; + ioformat const& format_; + }; + + template + std::ostream& operator<<(std::ostream& os, const format& f) + { + if constexpr(concepts::eigen_compatible) return os << f.matrix_.format(f.format_); + else return os << f.matrix_.base().format(f.format_); + } +} diff --git a/include/rotgen/impl/block_model.hpp b/include/rotgen/impl/block_model.hpp index 7bd4abc..58eab26 100644 --- a/include/rotgen/impl/block_model.hpp +++ b/include/rotgen/impl/block_model.hpp @@ -96,6 +96,7 @@ class ROTGEN_EXPORT CLASSNAME SOURCENAME div(TYPE s) const; friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&,CLASSNAME const&); + friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&, format const&); friend ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs); friend ROTGEN_EXPORT bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs); diff --git a/include/rotgen/impl/map_model.hpp b/include/rotgen/impl/map_model.hpp index 41c4c8c..9f69792 100644 --- a/include/rotgen/impl/map_model.hpp +++ b/include/rotgen/impl/map_model.hpp @@ -106,7 +106,8 @@ class ROTGEN_EXPORT CLASSNAME SOURCENAME inverse() const; - friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&,CLASSNAME const&); + friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&, CLASSNAME const&); + friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&, format const&); const TYPE* data() const; #if !defined(USE_CONST) diff --git a/include/rotgen/impl/matrix.hpp b/include/rotgen/impl/matrix.hpp index 5953439..dd1e5a8 100644 --- a/include/rotgen/impl/matrix.hpp +++ b/include/rotgen/impl/matrix.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include diff --git a/include/rotgen/impl/matrix_model.hpp b/include/rotgen/impl/matrix_model.hpp index a9bb1d1..2aa814b 100644 --- a/include/rotgen/impl/matrix_model.hpp +++ b/include/rotgen/impl/matrix_model.hpp @@ -76,6 +76,7 @@ class ROTGEN_EXPORT CLASSNAME CLASSNAME& operator/=(TYPE d); friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&,CLASSNAME const&); + friend ROTGEN_EXPORT std::ostream& operator<<(std::ostream&, format const&); friend ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs); friend ROTGEN_EXPORT bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs); diff --git a/include/rotgen/impl/payload.hpp b/include/rotgen/impl/payload.hpp index 39c52e4..72ec4b5 100644 --- a/include/rotgen/impl/payload.hpp +++ b/include/rotgen/impl/payload.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace rotgen { @@ -181,4 +182,19 @@ namespace rotgen payload (double* ptr, Index r, Index c) : data(ptr,r,c) {} payload (double* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} }; + + // + struct ioformat::payload + { + Eigen::IOFormat instance; + + payload ( int p, int f + , std::string const& cs, std::string const& rsp + , std::string const& rp, std::string const& rs + , std::string const& mp, std::string const& ms + , char fill + ) + : instance(p,f,cs,rsp,rp,rs,mp,ms,fill) + {} + }; } diff --git a/include/rotgen/rotgen.hpp b/include/rotgen/rotgen.hpp index 1787d10..bd42479 100644 --- a/include/rotgen/rotgen.hpp +++ b/include/rotgen/rotgen.hpp @@ -17,11 +17,13 @@ #include #include #include +#include #else #include #include #include #include +#include #endif #include diff --git a/src/block_indirect.cpp b/src/block_indirect.cpp index 283ff16..0e08f39 100644 --- a/src/block_indirect.cpp +++ b/src/block_indirect.cpp @@ -1,59 +1,66 @@ - #define SIZE 64 - #define TYPE double - #define STORAGE_ORDER Eigen::ColMajor +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#define SIZE 64 +#define TYPE double +#define STORAGE_ORDER Eigen::ColMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_col) - #include "block_model.cpp" - #undef CLASSNAME - #undef TRANSSOURCENAME - #undef SOURCENAME - #undef MAPNAME - #undef STORAGE_ORDER +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_col) +#include "block_model.cpp" +#undef CLASSNAME +#undef TRANSSOURCENAME +#undef SOURCENAME +#undef MAPNAME +#undef STORAGE_ORDER - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_row) - #include "block_model.cpp" - #undef CLASSNAME - #undef TRANSSOURCENAME - #undef SOURCENAME - #undef MAPNAME - #undef STORAGE_ORDER +#define STORAGE_ORDER Eigen::RowMajor +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_row) +#include "block_model.cpp" +#undef CLASSNAME +#undef TRANSSOURCENAME +#undef SOURCENAME +#undef MAPNAME +#undef STORAGE_ORDER - #undef SIZE - #undef TYPE +#undef SIZE +#undef TYPE - #define SIZE 32 - #define TYPE float - #define STORAGE_ORDER Eigen::ColMajor +#define SIZE 32 +#define TYPE float +#define STORAGE_ORDER Eigen::ColMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_col) - #include "block_model.cpp" - #undef CLASSNAME - #undef TRANSSOURCENAME - #undef SOURCENAME - #undef MAPNAME - #undef STORAGE_ORDER +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_col) +#include "block_model.cpp" +#undef CLASSNAME +#undef TRANSSOURCENAME +#undef SOURCENAME +#undef MAPNAME +#undef STORAGE_ORDER - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_row) - #include "block_model.cpp" - #undef CLASSNAME - #undef TRANSSOURCENAME - #undef SOURCENAME - #undef MAPNAME - #undef STORAGE_ORDER +#define STORAGE_ORDER Eigen::RowMajor +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#define MAPNAME ROTGEN_MATRIX_NAME(BASEMAP,SIZE,_row) +#include "block_model.cpp" +#undef CLASSNAME +#undef TRANSSOURCENAME +#undef SOURCENAME +#undef MAPNAME +#undef STORAGE_ORDER - #undef SIZE - #undef TYPE \ No newline at end of file +#undef SIZE +#undef TYPE \ No newline at end of file diff --git a/src/block_model.cpp b/src/block_model.cpp index 6ca61e2..889ecc1 100644 --- a/src/block_model.cpp +++ b/src/block_model.cpp @@ -394,6 +394,12 @@ struct CLASSNAME::payload return os; } + ROTGEN_EXPORT std::ostream& operator<<(std::ostream& os,format const& m) + { + m.matrix_.storage_->apply([&](const auto& blk) { os << blk.format(m.format_.storage()->instance); }); + return os; + } + ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs) { return std::visit ( [](auto const& lhs_blk, auto const& rhs_blk) { return lhs_blk.first == rhs_blk.first; } diff --git a/src/format.cpp b/src/format.cpp new file mode 100644 index 0000000..474a13b --- /dev/null +++ b/src/format.cpp @@ -0,0 +1,27 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== + +#include +#include +#include +#include +#include + +namespace rotgen +{ + ioformat::ioformat( int p, int f + , std::string const& cs, std::string const& rsp + , std::string const& rp, std::string const& rs + , std::string const& mp, std::string const& ms + , char fill + ) + : storage_(std::make_unique(p,f,cs,rsp,rp,rs,mp,ms,fill)) + {} + + ioformat::~ioformat() = default; +} \ No newline at end of file diff --git a/src/map_indirect.cpp b/src/map_indirect.cpp index 402d394..fed2ac7 100644 --- a/src/map_indirect.cpp +++ b/src/map_indirect.cpp @@ -1,67 +1,74 @@ - #define SIZE 64 - #define TYPE double - #define STORAGE_ORDER Eigen::ColMajor +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#define SIZE 64 +#define TYPE double +#define STORAGE_ORDER Eigen::ColMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) - #define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "map_model.cpp" - #undef CLASSNAME - #undef TRANSCLASSNAME - #undef TRANSSOURCENAME - #undef CLASSCONSTNAME - #undef SOURCENAME - #undef STORAGE_ORDER +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) +#define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#include "map_model.cpp" +#undef CLASSNAME +#undef TRANSCLASSNAME +#undef TRANSSOURCENAME +#undef CLASSCONSTNAME +#undef SOURCENAME +#undef STORAGE_ORDER - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) - #define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "map_model.cpp" - #undef CLASSNAME - #undef TRANSCLASSNAME - #undef TRANSSOURCENAME - #undef SOURCENAME - #undef CLASSCONSTNAME - #undef STORAGE_ORDER +#define STORAGE_ORDER Eigen::RowMajor +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) +#define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#include "map_model.cpp" +#undef CLASSNAME +#undef TRANSCLASSNAME +#undef TRANSSOURCENAME +#undef SOURCENAME +#undef CLASSCONSTNAME +#undef STORAGE_ORDER - #undef SIZE - #undef TYPE +#undef SIZE +#undef TYPE - #define SIZE 32 - #define TYPE float - #define STORAGE_ORDER Eigen::ColMajor +#define SIZE 32 +#define TYPE float +#define STORAGE_ORDER Eigen::ColMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) - #define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "map_model.cpp" - #undef CLASSNAME - #undef TRANSCLASSNAME - #undef TRANSSOURCENAME - #undef CLASSCONSTNAME - #undef SOURCENAME - #undef STORAGE_ORDER +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) +#define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#include "map_model.cpp" +#undef CLASSNAME +#undef TRANSCLASSNAME +#undef TRANSSOURCENAME +#undef CLASSCONSTNAME +#undef SOURCENAME +#undef STORAGE_ORDER - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) - #define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) - #define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "map_model.cpp" - #undef CLASSNAME - #undef TRANSCLASSNAME - #undef TRANSSOURCENAME - #undef CLASSCONSTNAME - #undef SOURCENAME - #undef STORAGE_ORDER +#define STORAGE_ORDER Eigen::RowMajor +#define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) +#define TRANSCLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) +#define TRANSSOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) +#define CLASSCONSTNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) +#define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) +#include "map_model.cpp" +#undef CLASSNAME +#undef TRANSCLASSNAME +#undef TRANSSOURCENAME +#undef CLASSCONSTNAME +#undef SOURCENAME +#undef STORAGE_ORDER - #undef SIZE - #undef TYPE +#undef SIZE +#undef TYPE diff --git a/src/map_model.cpp b/src/map_model.cpp index 56e1a7f..da87ce3 100644 --- a/src/map_model.cpp +++ b/src/map_model.cpp @@ -265,6 +265,11 @@ return os << m.storage_->data; } + ROTGEN_EXPORT std::ostream& operator<<(std::ostream& os,format const& m) + { + return os << m.matrix_.storage_->data.format(m.format_.storage()->instance); + } + ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs) { return lhs.storage_->data == rhs.storage_->data; diff --git a/src/matrix_model.cpp b/src/matrix_model.cpp index 96c8de2..a4131d7 100644 --- a/src/matrix_model.cpp +++ b/src/matrix_model.cpp @@ -175,6 +175,11 @@ ROTGEN_EXPORT std::ostream& operator<<(std::ostream& os,CLASSNAME const& m) return os << m.storage_->data; } +ROTGEN_EXPORT std::ostream& operator<<(std::ostream& os,format const& m) +{ + return os << m.matrix_.storage_->data.format(m.format_.storage()->instance); +} + ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs) { return lhs.storage_->data == rhs.storage_->data; diff --git a/test/unit/io.cpp b/test/integration/io.cpp similarity index 55% rename from test/unit/io.cpp rename to test/integration/io.cpp index 698063c..be69613 100644 --- a/test/unit/io.cpp +++ b/test/integration/io.cpp @@ -45,3 +45,42 @@ TTS_CASE_TPL("I/O for map test", rotgen::tests::types) if constexpr(O::value) TTS_EQUAL(os.str(), std::string{"1 2\n3 4"}); else TTS_EQUAL(os.str(), std::string{"1 3\n2 4"}); }; + +TTS_CASE_TPL("I/O using format", rotgen::tests::types) +( tts::type< tts::types> ) +{ + rotgen::ioformat io(rotgen::StreamPrecision, 0, ", ", ";\n", "<", ">", "[", "]"); + + rotgen::matrix x({ {1,2} , {3,4} }); + + { + std::ostringstream os; + os << rotgen::format(x,io); + TTS_EQUAL(os.str(), std::string{"[<1, 2>;\n <3, 4>]"}); + } + + rotgen::map> m{x.data()}; + { + std::ostringstream os; + os << rotgen::format(m,io); + TTS_EQUAL(os.str(), std::string{"[<1, 2>;\n <3, 4>]"}); + } + + auto b = rotgen::extract(x,0,0,2,2); + { + std::ostringstream os; + os << rotgen::format(b,io); + TTS_EQUAL(os.str(), std::string{"[<1, 2>;\n <3, 4>]"}); + } + + auto printer = [&](rotgen::ref> r) + { + std::ostringstream st; + st << rotgen::format(r,io); + return st.str(); + }; + + TTS_EQUAL(printer(x), std::string{"[<1, 2>;\n <3, 4>]"}); + TTS_EQUAL(printer(m), std::string{"[<1, 2>;\n <3, 4>]"}); + TTS_EQUAL(printer(b), std::string{"[<1, 2>;\n <3, 4>]"}); +};