wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
Serializer.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <QDataStream>
7#include <QFile>
8#include <QSaveFile>
9#include <QStandardItemModel>
10
12#include "App/Core/Common.h"
13
14namespace DolphinSerializer {
15
16void saveBinary(QDataStream &stream, const QStandardItemModel *model, const int inputPorts)
17{
18 // .dolphin format: inputPortCount | columnCount | values (col-major, inputs only)
19 // Output rows are not saved because they are deterministically computed by run()
20 stream << static_cast<qint64>(inputPorts);
21 stream << static_cast<qint64>(model->columnCount());
22
23 for (int col = 0; col < model->columnCount(); ++col) {
24 for (int row = 0; row < inputPorts; ++row) {
25 stream << static_cast<qint64>(model->index(row, col).data().toInt());
26 }
27 }
28}
29
30WaveformData loadBinary(QDataStream &stream, const int maxInputPorts)
31{
32 qint64 rows; stream >> rows;
33 qint64 cols; stream >> cols;
34
35 if (rows < 0) {
36 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid number of rows.");
37 }
38 if (rows > maxInputPorts) {
39 qCWarning(zero) << "DolphinSerializer: truncating waveform from" << rows << "rows to maximum" << maxInputPorts;
40 rows = maxInputPorts;
41 }
42
43 if ((cols < 2) || (cols > SignalModel::kMaxColumns)) {
44 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin",
45 "Invalid number of columns: got %1, expected between 2 and %2.",
46 QString::number(cols), QString::number(SignalModel::kMaxColumns));
47 }
48
49 WaveformData data;
50 data.inputPorts = static_cast<int>(rows);
51 data.columns = static_cast<int>(cols);
52 data.values.resize(static_cast<qsizetype>(data.inputPorts) * data.columns);
53
54 // Binary format is col-major; normalize to row-major for the caller
55 for (int col = 0; col < data.columns; ++col) {
56 for (int row = 0; row < data.inputPorts; ++row) {
57 qint64 value; stream >> value;
58 data.values[row * data.columns + col] = static_cast<int>(value);
59 }
60 }
61
62 return data;
63}
64
65void saveCSV(QSaveFile &file, const QStandardItemModel *model)
66{
67 // CSV format: first line is "rows,cols,"; subsequent lines are comma-separated row values.
68 // Both input and output rows are written so the CSV is human-readable without re-running.
69 file.write(QString::number(model->rowCount()).toUtf8());
70 file.write(",");
71 file.write(QString::number(model->columnCount()).toUtf8());
72 file.write(",\n");
73
74 for (int row = 0; row < model->rowCount(); ++row) {
75 for (int col = 0; col < model->columnCount(); ++col) {
76 file.write(model->index(row, col).data().toString().toUtf8());
77 file.write(",");
78 }
79
80 file.write("\n");
81 }
82}
83
84WaveformData loadCSV(QFile &file, const int maxInputPorts)
85{
86 // CSV is a flat comma-separated byte array: "rows,cols,v00,v01,...,"
87 // (trailing comma on each row is tolerated; split(',') produces a trailing empty element)
88 const QByteArray content = file.readAll();
89 const auto wordList = content.split(',');
90
91 if (wordList.size() < 2) {
92 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid CSV format: insufficient data.");
93 }
94
95 int rows = wordList.at(0).toInt();
96 const int cols = wordList.at(1).toInt();
97
98 if (rows < 0) {
99 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid number of rows.");
100 }
101 if (rows > maxInputPorts) {
102 qCWarning(zero) << "DolphinSerializer: truncating waveform from" << rows << "rows to maximum" << maxInputPorts;
103 rows = maxInputPorts;
104 }
105
106 if ((cols < 2) || (cols > SignalModel::kMaxColumns)) {
107 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin",
108 "Invalid number of columns: got %1, expected between 2 and %2.",
109 QString::number(cols), QString::number(SignalModel::kMaxColumns));
110 }
111
112 // Validate before indexing to avoid out-of-bounds access on corrupt files
113 const qsizetype expectedSize = 2 + static_cast<qsizetype>(rows) * cols;
114 if (wordList.size() < expectedSize) {
115 // Pass QString so .arg() selects the variadic-string overload and avoids
116 // QString::arg(qlonglong, int)'s narrowing of the second qsizetype to int.
117 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin",
118 "Invalid CSV format: expected %1 elements, got %2.",
119 QString::number(expectedSize), QString::number(wordList.size()));
120 }
121
122 WaveformData data;
123 data.inputPorts = rows;
124 data.columns = cols;
125 data.values.resize(static_cast<qsizetype>(rows) * cols);
126
127 // CSV values are stored row-major: index = 2 + row*cols + col
128 bool hadInvalidValues = false;
129 for (int row = 0; row < rows; ++row) {
130 for (int col = 0; col < cols; ++col) {
131 const int raw = wordList.at(2 + col + row * cols).toInt();
132 if (raw != 0 && raw != 1) {
133 hadInvalidValues = true;
134 }
135 data.values[row * cols + col] = (raw == 1) ? 1 : 0;
136 }
137 }
138 if (hadInvalidValues) {
139 qCWarning(zero) << "DolphinSerializer: CSV contained non-binary cell values — clamped to 0/1";
140 }
141
142 return data;
143}
144
145} // namespace DolphinSerializer
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION_WITH_CONTEXT(context, msg,...)
Definition Common.h:102
DolphinSerializer: encoding and decoding of .dolphin and .csv waveform files.
SignalModel for the beWavedDolphin waveform table.
static constexpr int kMaxColumns
Definition SignalModel.h:38
Pure I/O functions for the beWavedDolphin waveform file formats.
void saveBinary(QDataStream &stream, const QStandardItemModel *model, const int inputPorts)
Serializes input rows to the binary .dolphin stream.
void saveCSV(QSaveFile &file, const QStandardItemModel *model)
Serializes all rows (inputs + outputs) to a .csv file.
WaveformData loadCSV(QFile &file, const int maxInputPorts)
Deserializes input rows from a .csv file.
WaveformData loadBinary(QDataStream &stream, const int maxInputPorts)
Deserializes input rows from a binary .dolphin stream.
Raw waveform data returned by the load functions.
Definition Serializer.h:33
int inputPorts
Number of input rows stored in values.
Definition Serializer.h:34
QVector< int > values
Cell values in row-major order (inputs only): index = row * columns + col.
Definition Serializer.h:37