436 return internalLoadJITData(filename, minWidth, maxHeight, options);
441 return internalLoadCSVFile(filename, minWidth, maxHeight, options, buffer);
445template<
class T,
class ReadWriteT>
448 bool print_dimensions,
449 bool saveEvenIfAllZero)
const
452 return internalSaveCSVFile(filename, precision, print_dimensions, predicate, saveEvenIfAllZero);
455template<
class T,
class ReadWriteT>
456template<
class PredicateT>
459 bool print_dimensions,
460 PredicateT& predicate,
461 bool saveEvenIfAllZero)
const
463 return internalSaveCSVFile(filename, precision, print_dimensions, predicate, saveEvenIfAllZero);
466template<
class T,
class ReadWriteT>
470 assert(x < width and
"Invalid column index (bigger than `this->width`)");
475 if (Yuni::Static::Type::StrictlyEqual<T, U>::Yes)
477 (void)::memcpy(column, data,
sizeof(T) * height);
482 for (uint y = 0; y != height; ++y)
484 column[y] = (T)data[y];
491template<
class T,
class ReadWriteT>
494 assert(x < width and
"Invalid column index (bigger than `this->width`)");
497 for (uint y = 0; y != height; ++y)
505template<
class T,
class ReadWriteT>
508 assert(x < width and
"Invalid column index (bigger than `this->width`)");
511 (void)::memset((
void*)column, 0,
sizeof(T) * height);
516template<
class T,
class ReadWriteT>
521 jit->markAsModified();
525template<
class T,
class ReadWriteT>
528 return (!width) or (!height);
531template<
class T,
class ReadWriteT>
536 for (uint i = 0; i != width; ++i)
547template<
class T,
class ReadWriteT>
554template<
class T,
class ReadWriteT>
560 assert(w <= 50000 and
"The new width seems a bit excessive");
561 assert(h <= 50000 and
"The new height seems a bit excessive");
564 if (w != width or h != height)
574 for (uint i = 0; i != width; ++i)
593 entry =
new typename Antares::Memory::Stored<T>::Type[width + 1];
594 entry[width] =
nullptr;
596 for (uint i = 0; i != w; ++i)
598 Antares::Memory::Allocate<T>(entry[i], height);
610 if (jit and w != 0 and h != 0)
616 jit->options = jit->options | optFixedSize;
624static inline bool DetectEncoding(
const AnyString& filename,
const AnyString& data,
size_t& offset)
629 if ((
unsigned char)data[0] == 0xFE and ((
unsigned char)data[1]) == 0xFF)
631 if (data.size() > 3 and !data[2] and !data[3])
633 logs.error() <<
'`' << filename
634 <<
"`: UTF-32 Little Endian encoding detected. ASCII/UTF-8 required.";
638 logs.error() <<
'`' << filename
639 <<
"`: UTF-16 Big Endian encoding detected. ASCII/UTF-8 required.";
644 if ((
unsigned char)data[0] == 0xFF and ((
unsigned char)data[1]) == 0xFE)
646 logs.error() <<
'`' << filename
647 <<
"`: UTF-16 Little Endian encoding detected. ASCII/UTF-8 required.";
651 if ((
unsigned char)data[0] == 0xEF and ((
unsigned char)data[1]) == 0xBB and data.size() > 2
652 and ((
unsigned char)data[2]) == 0xBF)
659 if (!data[0] and !data[1] and ((
unsigned char)data[2]) == 0xFE
660 and ((
unsigned char)data[3]) == 0xFF)
662 logs.error() <<
'`' << filename
663 <<
"`: UTF-32 Big Endian encoding detected. ASCII/UTF-8 required.";
673template<
class T,
class ReadWriteT>
674bool Matrix<T, ReadWriteT>::loadFromBuffer(
const AnyString& filename,
681 using namespace Yuni;
684 logs.debug() <<
" :: loading `" << filename <<
"`";
690 if (not DetectEncoding(filename, data, bom))
693 reset((minWidth > 0 ? minWidth : 1), maxHeight);
697 uint offset = (uint)bom;
704 reset(minWidth, maxHeight,
true);
711 assert(not data.empty());
712 maxHeight = data.countChar(
'\n');
713 if (data.last() ==
'\n')
724 YString::Size max = data.find(
'\n');
725 if (max == BufferType::npos)
727 logs.error() << filename <<
": At least one line-return must be available";
728 reset(minWidth, maxHeight);
737 char c = data[max - 1];
738 if (c ==
'\r' or c ==
'\t' or c ==
' ')
752 if (max > 7 and data.startsWith(
"size:"))
754 CString<64, false> buffer;
755 buffer.assign(data.c_str(), max);
758 sscanf_s(buffer.c_str(),
"size:%dx%d", &x, &y);
760 sscanf(buffer.c_str(),
"size:%dx%d", &x, &y);
764 if (!(options & optQuiet))
766 logs.warning() <<
'`' << filename <<
"`: Invalid header";
772 if (!(options & optQuiet))
774 logs.warning() <<
'`' << filename <<
"`: Invalid header";
779 resize((uint)x, (uint)y);
784 x = ((max > 0) ? 1 : 0);
788 while ((offset = (uint)data.find_first_of(ANTARES_MATRIX_CSV_COMMA, offset)) < max)
794 resize(((x < minWidth) ? minWidth : x), maxHeight);
800 if (not(options & optQuiet) and not(options & optNoWarnIfEmpty))
802 logs.warning() <<
"`" << filename <<
"`: Invalid format: The file seems empty";
815 char separator =
'\0';
817 ReadWriteType cellValue;
820 while (y < maxHeight and offset < (uint)data.size())
825 uint lineOffset = (uint)offset;
827 while ((offset = data.find_first_of(ANTARES_MATRIX_CSV_SEPARATORS, offset))
830 assert(offset != BufferType::npos);
832 separator = data[offset];
836 converter = (
const char*)((
const char*)data.c_str() + pos);
839 if (not converter.empty())
843 if ((options & optNeverFails))
845 if (separator ==
'\n')
847 resizeWithoutDataLost(x + 1, height);
853 uint newOffset = offset;
854 uint newWidth = width + 1;
856 while ((newOffset = data.find_first_of(ANTARES_MATRIX_CSV_SEPARATORS,
857 (String::Size)newOffset))
860 if (data[newOffset] ==
'\n')
865 if (data[newOffset] !=
'\r')
871 resizeWithoutDataLost(newWidth, height);
878 if (not(options & optQuiet) and errorCount > 0)
881 <<
'`' << filename <<
"`: Invalid format: Too many entry for the row "
882 << y <<
" (offset: " << (uint)pos <<
"byte)";
885 logs.warning() <<
" ... (skipped)";
892 if (MatrixStringConverter<ReadWriteType>::direct)
897 MatrixData<T>::Copy(entry[x][y], converter);
903 if (not MatrixStringConverter<ReadWriteType>::Do(converter, cellValue))
908 if (not MatrixStringConverter<double>::Do(converter, fallback))
911 if (not(options & optQuiet) and errorCount)
914 <<
'`' << filename <<
"`: Invalid numeric value (x:" << x
915 <<
",y:" << y <<
", offset: " << (uint)pos <<
"byte), text: `"
916 << converter <<
" read:" << entry[x][y] <<
'`';
917 if (not(--errorCount))
919 logs.warning() <<
" ... (skipped)";
922 MatrixData<T>::Init(entry[x][y]);
926 entry[x][y] = MatrixRound<T, ReadWriteType>::Value(
927 static_cast<ReadWriteType
>(fallback));
933 MatrixData<T>::Copy(entry[x][y], cellValue);
942 MatrixData<T>::Init(entry[x][y]);
943 if (not(options & optQuiet))
945 logs.debug() <<
" empty value at " << (x + 1) <<
'x' << (y + 1)
946 <<
" (line offset: " << (offset - lineOffset) <<
")";
958 if (separator ==
'\r')
960 if (data[offset] ==
'\n')
968 if (separator ==
'\n')
978 if (not(options & optNeverFails))
981 if (not(options & optQuiet) and errorCount)
984 << filename <<
": at line " << (y + 1) <<
", not enough columns (expected "
985 << width <<
", got " << x <<
')';
986 if (not(--errorCount))
988 logs.warning() <<
" ... (skipped)";
994 MatrixData<T>::Init(entry[x][y]);
1008 if (!(options & optQuiet))
1010 logs.warning() << filename <<
": not enough rows (expected " << height <<
", got " << y
1016 for (x = 0; x < width; ++x)
1018 MatrixData<T>::Init(entry[x][y]);
1024 return ((0 != (options & optNeverFails)) ?
true : result);
1027template<
class T,
class ReadWriteT>
1028bool Matrix<T, ReadWriteT>::internalLoadCSVFile(
const AnyString& filename,
1035 bool result =
false;
1037 const bool hasOwnership = (NULL == buffer);
1040 buffer =
new BufferType();
1043 switch (loadFromFileToBuffer(*buffer, filename))
1045 case Yuni::IO::errNone:
1048 if (buffer->empty())
1050 if (maxHeight and minWidth)
1052 reset((minWidth != 0 ? minWidth : 1),
1064 Statistics::HasReadFromDisk(buffer->size());
1069 result = loadFromBuffer(filename,
1073 (options & optFixedSize),
1077 if (0 != (options & optMarkAsModified))
1081 jit->markAsModified();
1086 case Yuni::IO::errNotFound:
1088 if (not(options & optQuiet))
1090 logs.error() <<
"I/O Error: not found: '" << filename <<
"'";
1094 case Yuni::IO::errMemoryLimit:
1096 if (not(options & optQuiet))
1098 logs.error() << filename <<
": The file is too large (>"
1099 << (filesizeHardLimit / 1024 / 1024) <<
"Mo)";
1105 if (not(options & optQuiet))
1107 logs.error() <<
"I/O Error: failed to load '" << filename <<
"'";
1121 reset(minWidth, maxHeight);
1125 if (
JIT::enabled and not jit and (0 != (options & optFixedSize)))
1132 jit->alreadyLoaded =
true;
1133 jit->modified =
false;
1134 jit->minWidth = (options & optFixedSize) ? (!width ? minWidth : width) : 1;
1135 jit->maxHeight = height;
1136 jit->options = options;
1137 if (jit->sourceFilename.empty())
1139 jit->sourceFilename = filename;
1140 assert(not jit->sourceFilename.empty());
1149template<
class T,
class ReadWriteT>
1152 if (width and height)
1154 for (uint x = 0; x != width; ++x)
1156 auto& column = entry[x];
1157 for (uint y = 0; y != height; ++y)
1159 if (!Utils::isZero((T)column[y]))
1169template<
class T,
class ReadWriteT>
1170template<
class PredicateT>
1173 if (width and height)
1175 for (uint x = 0; x != width; ++x)
1177 auto& column = entry[x];
1178 for (uint y = 0; y != height; ++y)
1180 if (!Utils::isZero((T)predicate(column[y])))
1190template<
class T,
class ReadWriteT>
1191template<
class PredicateT>
1194 bool print_dimensions,
1195 PredicateT& predicate,
1196 bool saveEvenIfAllZero)
const
1198 using namespace Yuni;
1203 isDecimal = Static::Type::IsDecimal<ReadWriteType>::Yes,
1206 if (not print_dimensions and (containsOnlyZero(predicate) and not saveEvenIfAllZero))
1212 matrix_to_buffer_dumper_factory mtx_to_buffer_dumper_factory;
1214 I_mtx_to_buffer_dumper<T, ReadWriteT, PredicateT>* mtx_to_buffer_dpr
1215 = mtx_to_buffer_dumper_factory.get_dumper<T, ReadWriteT, PredicateT>(
this, data, predicate);
1218 mtx_to_buffer_dpr->set_print_format(isDecimal, precision);
1221 data.reserve(width * height * 6);
1223 if (print_dimensions)
1225 data +=
"size:" + std::to_string(width) +
'x' + std::to_string(height) +
'\n';
1228 mtx_to_buffer_dpr->run();
1231template<
class T,
class ReadWriteT>
1232void Matrix<T, ReadWriteT>::saveToBuffer(std::string& data, uint precision)
const
1235 this->saveToBuffer(data, precision,
false, identity,
true);
1238template<
class T,
class ReadWriteT>
1241 if (not file.openRW(filename))
1243 logs.error() <<
"I/O error: " << filename
1244 <<
": Impossible to write the file (not enough permission ?)";
1250template<
class T,
class ReadWriteT>
1256template<
class T,
class ReadWriteT>
1257template<
class PredicateT>
1258bool Matrix<T, ReadWriteT>::internalSaveCSVFile(
const AnyString& filename,
1260 bool print_dimensions,
1261 PredicateT& predicate,
1262 bool saveEvenIfAllZero)
const
1266 jit_mgr.record_current_jit_state(width, height);
1268 if (jit_mgr.jit_activated() && jit_mgr.matrix_content_in_memory_is_same_as_on_disk())
1273 jit_mgr.clear_matrix(
this);
1277 if (jit_mgr.jit_activated() && jit_mgr.do_we_force_matrix_load_from_disk())
1279 jit_mgr.load_matrix(
this);
1285 logs.debug() <<
" :: writing `" << filename <<
"' (" << width <<
'x' << height <<
')';
1288 Yuni::IO::File::Stream file;
1289 if (not openFile(file, filename))
1294 if (height and width)
1298 saveToBuffer(buffer, precision, print_dimensions, predicate, saveEvenIfAllZero);
1299 Statistics::HasWrittenToDisk(buffer.size());
1301 saveBufferToFile(buffer, file);
1307 logs.debug() <<
" :: [end] writing `" << filename <<
"' (" << width <<
'x' << height <<
')';
1310 jit_mgr.unload_matrix_properly_from_memory(
this);
1315template<
class T,
class ReadWriteT>
1324 if (x <= width and y <= height)
1326 for (uint i = x; i < width; ++i)
1340 uint minW = (x < copy.
width) ? x : copy.
width;
1343 for (uint i = 0; i < minW; ++i)
1347 (void)::memcpy(column, copy.
entry[i],
sizeof(T) * minH);
1349 for (uint j = minH; j < y; ++j)
1357 for (uint i = minW; i < x; ++i)
1359 Memory::Zero(y, entry[i]);
1364 for (uint i = minW; i < x; ++i)
1366 Memory::Assign(y, entry[i], defVal);
1372 logs.debug() <<
" :: end resizeWithoutDataLost";
1375template<
class T,
class ReadWriteT>
1381 ->loadFromCSVFile(jit->sourceFilename,
1384 jit->options | optImmediate);
1389template<
class T,
class ReadWriteT>
1398 if (!Utils::isZero(c))
1400 for (uint x = 0; x != width; ++x)
1404 for (uint y = 0; y != height; ++y)
1416template<
class T,
class ReadWriteT>
1420 assert(x < width and
"Invalid column index (bigger than `this->width`)");
1422 for (uint y = 0; y != height; ++y)
1428template<
class T,
class ReadWriteT>
1432 assert(x < width and
"Invalid column index (bigger than `this->width`)");
1433 assert(c != (T)0 &&
"Dividing by zero");
1434 ColumnType& column = entry[x];
1435 for (uint y = 0; y != height; ++y)
1441template<
class T,
class ReadWriteT>
1444 for (uint x = 0; x != width; ++x)
1447 for (uint y = 0; y != height; ++y)
1449 col[y] = (T)std::round(col[y]);
1454template<
class T,
class ReadWriteT>
1457 for (uint x = 0; x != width; ++x)
1460 for (uint y = 0; y != height; ++y)
1462 col[y] = std::abs(col[y]);
1467template<
class T,
class ReadWriteT>
1471 for (uint x = 0; x != width; ++x)
1474 for (uint y = 0; y != height; ++y)
1485template<
class T,
class ReadWriteT>
1489 for (uint x = 0; x != width; ++x)
1492 for (uint y = 0; y != height; ++y)
1503template<
class T,
class ReadWriteT>
1504template<
class U,
class V>
1507 assert((
void*)(&rhs) != (
void*)
this and
"Undefined behavior");
1519 for (uint x = 0; x != rhs.
width; ++x)
1521 auto& column = entry[x];
1522 const auto& src = rhs.
entry[x];
1526 if (Yuni::Static::Type::StrictlyEqual<T, U>::Yes)
1528 (void)::memcpy((
void*)column, (
void*)src,
sizeof(T) * height);
1533 for (uint y = 0; y != height; ++y)
1535 column[y] = (T)src[y];
1558template<
class T,
class ReadWriteT>
1559template<
class U,
class V>
1568template<
class T,
class ReadWriteT>
1573 swap(this->width, rhs.
width);
1574 swap(this->height, rhs.
height);
1575 swap(this->entry, rhs.
entry);
1576 swap(this->jit, rhs.
jit);
1579template<
class T,
class ReadWriteT>
1586template<
class T,
class ReadWriteT>
1592 if (0 == width || 0 == height)
1603 rhs.
entry =
nullptr;
1607template<
class T,
class ReadWriteT>
1615template<
class T,
class ReadWriteT>
1618 std::cout <<
"DUMP:\n";
1621 std::cout <<
"\tempty\n";
1624 for (uint y = 0; y != height; ++y)
1627 for (uint x = 0; x != width; ++x)
1637 std::cout << entry[x][y];
1643template<
class T,
class ReadWriteT>
1648 if (jit->alreadyLoaded and not jit->modified and not jit->sourceFilename.empty())
1651 auto& thisNotConst =
const_cast<Matrix&
>(*this);
1653 thisNotConst.
clear();
1659template<
class T1,
class T2>
1660bool MatrixTestForAtLeastOnePositiveValue(
const Matrix<T1, T2>& m)
1665 for (uint x = 0; x < m.
width; ++x)
1667 auto& col = m.
entry[x];
1668 for (y = 0; y < m.
height; ++y)
1680template<
class T,
class ReadWriteT>
1685 for (uint column = 0; column != width; ++column)
1687 circularShiftRows(column, count);
1693template<
class T,
class ReadWriteT>
1696 if (height <= 1 or !(column < width) or !(start < end))
1702 auto& values = entry[column];
1705 for (uint y = start; y < --end; ++y)
1708 values[y] = values[end];
1713template<
class T,
class ReadWriteT>
1716 assert(column < width and
"Column out of bounds");
1717 if (height <= 1 or !(column < width) or !count)
1723 count = (count % height + height) % height;
1724 if (count == 0 or (uint) count == height)
1730 reverseRows(column, 0, count);
1731 reverseRows(column, count, height);
1732 reverseRows(column, 0, height);
1736template<
class T,
class ReadWriteT>
1740 assert(column < width);
1741 assert(Memory::RawPointer(entry[column]));
1742 return entry[column];
1745template<
class T,
class ReadWriteT>
1748 assert(column < width);
1749 assert(Memory::RawPointer(entry[column]));
1750 return entry[column];