OdbDesignLib
OdbDesign ODB++ Parsing Library
 
Loading...
Searching...
No Matches
MatrixFile.cpp
1//
2// Created by nmill on 10/13/2023.
3//
4
5#include "MatrixFile.h"
6#include <fstream>
7#include "str_utils.h"
8#include <string>
9#include "../../Constants.h"
10#include <sstream>
11#include "../parse_error.h"
12#include <Logger.h>
13#include "../invalid_odb_error.h"
14#include "enums.pb.h"
15#include "../../enums.h"
16#include "../OdbFile.h"
17#include <memory>
18#include <ostream>
19
20namespace Odb::Lib::FileModel::Design
21{
22 MatrixFile::~MatrixFile()
23 {
24 m_layerRecords.clear();
25 m_stepRecords.clear();
26 }
27
28 const MatrixFile::LayerRecord::Vector& MatrixFile::GetLayerRecords() const
29 {
30 return m_layerRecords;
31 }
32
33 const MatrixFile::StepRecord::Vector& MatrixFile::GetStepRecords() const
34 {
35 return m_stepRecords;
36 }
37
38 bool MatrixFile::Parse(std::filesystem::path path)
39 {
40 std::ifstream matrixFile;
41 int lineNumber = 0;
42 std::string line;
43
44 try
45 {
46 if (!OdbFile::Parse(path)) return false;
47
48 auto matrixFilePath = path / "matrix";
49 if (!std::filesystem::exists(matrixFilePath))
50 {
51 auto message = "matrix/matrix file does not exist: [" + matrixFilePath.string() + "]";
52 throw invalid_odb_error(message.c_str());
53 }
54
55 matrixFile.open(matrixFilePath, std::ios::in);
56 if (!matrixFile.is_open())
57 {
58 auto message = "unable to open matrix/matrix file: [" + matrixFilePath.string() + "]";
59 throw invalid_odb_error(message.c_str());
60 }
61
62 std::shared_ptr<StepRecord> pCurrentStepRecord;
63 std::shared_ptr<LayerRecord> pCurrentLayerRecord;
64 bool openBraceFound = false;
65
66 while (std::getline(matrixFile, line))
67 {
68 lineNumber++;
69 // trim whitespace from beginning and end of line
70 Utils::str_trim(line);
71 if (!line.empty())
72 {
73 std::stringstream lineStream(line);
74 if (line.find(Constants::COMMENT_TOKEN) == 0)
75 {
76 // comment line
77 }
78 else if (line.find(StepRecord::RECORD_TOKEN) == 0)
79 {
80 std::string token;
81 if (!(lineStream >> token))
82 {
83 throw_parse_error(m_path, line, token, lineNumber);
84 }
85
86 // any existing previous step record
87 if (token != StepRecord::RECORD_TOKEN || pCurrentStepRecord != nullptr)
88 {
89 throw_parse_error(m_path, line, token, lineNumber);
90 }
91
92 // open a new STEP array record
93 pCurrentStepRecord = std::make_shared<StepRecord>();
94
95 if (lineStream >> token)
96 {
97 // open brace is at the end on the same line
98 if (token == Constants::ARRAY_RECORD_OPEN_TOKEN)
99 {
100 openBraceFound = true;
101 }
102 }
103 }
104 else if (line.find(LayerRecord::RECORD_TOKEN) == 0)
105 {
106 std::string token;
107 if (!(lineStream >> token))
108 {
109 throw_parse_error(m_path, line, token, lineNumber);
110 }
111
112 // any existing previous layer record
113 if (token != LayerRecord::RECORD_TOKEN || pCurrentLayerRecord != nullptr)
114 {
115 throw_parse_error(m_path, line, token, lineNumber);
116 }
117
118 // open a new LAYER array record
119 pCurrentLayerRecord = std::make_shared<LayerRecord>();
120
121 if (lineStream >> token)
122 {
123 // open brace is on same line
124 if (token == Constants::ARRAY_RECORD_OPEN_TOKEN)
125 {
126 openBraceFound = true;
127 }
128 }
129 }
130 else if (line.find(Constants::ARRAY_RECORD_OPEN_TOKEN) == 0)
131 {
132 // TODO: how to determine if you are opening a step or layer array record?
133 // (maybe a boolean flag? stepArrayOpen = true/false)
134
135 // no current opening of a layer or step array record found yet
136 if (pCurrentStepRecord == nullptr && pCurrentLayerRecord == nullptr)
137 {
138 throw_parse_error(m_path, line, "", lineNumber);
139 }
140
141 // found another open brace while still parsing after the previous record's open brace
142 if (openBraceFound)
143 {
144 throw_parse_error(m_path, line, "", lineNumber);
145 }
146
147 openBraceFound = true;
148
149 // TODO: finish any existing previous layer or step record
150 // (same code as finding a close brace on an empty line)
151
152 // open a new LAYER array record
153 //pCurrentLayerRecord = std::make_shared<LayerRecord>();
154 }
155 else if (line.find(Constants::ARRAY_RECORD_CLOSE_TOKEN) == 0)
156 {
157 if (pCurrentStepRecord != nullptr && openBraceFound)
158 {
159 m_stepRecords.push_back(pCurrentStepRecord);
160 pCurrentStepRecord.reset();
161 openBraceFound = false;
162 }
163 else if (pCurrentLayerRecord != nullptr && openBraceFound)
164 {
165 m_layerRecords.push_back(pCurrentLayerRecord);
166 pCurrentLayerRecord.reset();
167 openBraceFound = false;
168 }
169 else
170 {
171 // found a close brace but aren't currently parsing a step or layer array record
172 throw_parse_error(m_path, line, "", lineNumber);
173 }
174 }
175 else
176 {
177 // it should be a name-value pair line (i.e. element of a step or layer array)
178 std::string attribute;
179 std::string value;
180
181 if (!std::getline(lineStream, attribute, '='))
182 {
183 throw_parse_error(m_path, line, attribute, lineNumber);
184 }
185
186 if (std::getline(lineStream, value))
187 {
188 Utils::str_trim(attribute);
189 Utils::str_trim(value);
190
191 if (pCurrentStepRecord != nullptr && openBraceFound)
192 {
193 if (attribute == StepRecord::COLUMN_KEY || attribute == "col")
194 {
195 pCurrentStepRecord->column = std::stoi(value);
196 }
197 else if (attribute == StepRecord::NAME_KEY || attribute == "name")
198 {
199 pCurrentStepRecord->name = value;
200 }
201 else if (attribute == StepRecord::ID_KEY || attribute == "id")
202 {
203 pCurrentStepRecord->id = static_cast<unsigned int>(std::stoul(value));
204 }
205 else
206 {
207 throw_parse_error(m_path, line, attribute, lineNumber);
208 }
209 }
210 else if (pCurrentLayerRecord != nullptr && openBraceFound)
211 {
212 if (attribute == "ROW" || attribute == "row")
213 {
214 pCurrentLayerRecord->row = std::stoi(value);
215 }
216 else if (attribute == "NAME" || attribute == "name")
217 {
218 pCurrentLayerRecord->name = value;
219 }
220 else if (attribute == "ID" || attribute == "id")
221 {
222 pCurrentLayerRecord->id = (unsigned int)std::stoul(value);
223 }
224 else if (attribute == "TYPE" || attribute == "type")
225 {
226 if (LayerRecord::typeMap.contains(value))
227 {
228 pCurrentLayerRecord->type = LayerRecord::typeMap.getValue(value);
229 }
230 else
231 {
232 throw_parse_error(m_path, line, attribute, lineNumber);
233 }
234 }
235 else if (attribute == LayerRecord::CONTEXT_KEY || attribute == "context")
236 {
237 if (LayerRecord::contextMap.contains(value))
238 {
239 pCurrentLayerRecord->context = LayerRecord::contextMap.getValue(value);
240 }
241 else
242 {
243 throw_parse_error(m_path, line, attribute, lineNumber);
244 }
245 }
246 else if (attribute == "OLD_NAME" || attribute == "old_name")
247 {
248 pCurrentLayerRecord->oldName = value;
249 }
250 else if (attribute == LayerRecord::POLARITY_KEY || attribute == "polarity")
251 {
252 if (LayerRecord::polarityMap.contains(value))
253 {
254 pCurrentLayerRecord->polarity = LayerRecord::polarityMap.getValue(value);
255 }
256 else
257 {
258 throw_parse_error(m_path, line, attribute, lineNumber);
259 }
260 }
261 else if (attribute == LayerRecord::DIELECTRIC_TYPE_KEY || attribute == "dielectric_type")
262 {
263 if (LayerRecord::dielectricTypeMap.contains(value))
264 {
265 pCurrentLayerRecord->dielectricType = LayerRecord::dielectricTypeMap.getValue(value);
266 }
267 else
268 {
269 throw_parse_error(m_path, line, attribute, lineNumber);
270 }
271 }
272 else if (attribute == "DIELECTRIC_NAME" || attribute == "dielectric_name")
273 {
274 pCurrentLayerRecord->dielectricName = value;
275 }
276 else if (attribute == LayerRecord::FORM_KEY || attribute == "form")
277 {
278 if (LayerRecord::formMap.contains(value))
279 {
280 pCurrentLayerRecord->form = LayerRecord::formMap.getValue(value);
281 }
282 else
283 {
284 throw_parse_error(m_path, line, attribute, lineNumber);
285 }
286 }
287 else if (attribute == "CU_TOP" || attribute == "cu_top")
288 {
289 pCurrentLayerRecord->cuTop = std::stoul(value);
290 }
291 else if (attribute == "CU_TOP" || attribute == "cu_top")
292 {
293 pCurrentLayerRecord->cuTop = std::stoul(value);
294 }
295 else if (attribute == "CU_BOTTOM" || attribute == "cu_bottom")
296 {
297 pCurrentLayerRecord->cuBottom = std::stoul(value);
298 }
299 else if (attribute == "REF" || attribute == "ref")
300 {
301 pCurrentLayerRecord->ref = std::stoul(value);
302 }
303 else if (attribute == "START_NAME" || attribute == "start_name")
304 {
305 pCurrentLayerRecord->startName = value;
306 }
307 else if (attribute == "END_NAME" || attribute == "end_name")
308 {
309 pCurrentLayerRecord->endName = value;
310 }
311 else if (attribute == "ADD_TYPE" || attribute == "add_type")
312 {
313 pCurrentLayerRecord->addType = value;
314 }
315 else if (attribute == "COLOR" || attribute == "color")
316 {
317 if (!pCurrentLayerRecord->color.from_string(value)) return false;
318 }
319 else
320 {
321 throw_parse_error(m_path, line, attribute, lineNumber);
322 }
323 }
324 else
325 {
326 // found a name-value pair but aren't currently parsing a step or layer array record
327 //return false;
328 throw_parse_error(m_path, line, attribute, lineNumber);
329 }
330 }
331 else if (!attributeValueIsOptional(attribute))
332 {
333 logwarn("matrix/matrix file: no value for non-optional attribute: " + attribute);
334 }
335 }
336 }
337 }
338
339 matrixFile.close();
340 }
341 catch (parse_error& pe)
342 {
343 auto m = pe.toString("Parse Error:");
344 logerror(m);
345 // cleanup file
346 matrixFile.close();
347 throw pe;
348 }
349 catch (invalid_odb_error& ioe)
350 {
351 parse_info pi(m_path, line, lineNumber);
352 const auto m = pi.toString();
353 logexception_msg(ioe, m);
354 // cleanup file
355 matrixFile.close();
356 throw ioe;
357 }
358
359 return true;
360 }
361
362 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile> Odb::Lib::FileModel::Design::MatrixFile::to_protobuf() const
363 {
364 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile> pMatrixFileMessage(new Odb::Lib::Protobuf::MatrixFile);
365 for (const auto& stepRecord : m_stepRecords)
366 {
367 auto pStepRecordMessage = pMatrixFileMessage->add_steps();
368 pStepRecordMessage->CopyFrom(*stepRecord->to_protobuf());
369 }
370 for (const auto& layerRecord : m_layerRecords)
371 {
372 auto pLayerRecordMessage = pMatrixFileMessage->add_layers();
373 pLayerRecordMessage->CopyFrom(*layerRecord->to_protobuf());
374 }
375 return pMatrixFileMessage;
376
377 }
378
379 void Odb::Lib::FileModel::Design::MatrixFile::from_protobuf(const Odb::Lib::Protobuf::MatrixFile& message)
380 {
381 for (const auto& stepRecord : message.steps())
382 {
383 auto pStepRecord = std::make_shared<StepRecord>();
384 pStepRecord->from_protobuf(stepRecord);
385 m_stepRecords.push_back(pStepRecord);
386 }
387 for (const auto& layerRecord : message.layers())
388 {
389 auto pLayerRecord = std::make_shared<LayerRecord>();
390 pLayerRecord->from_protobuf(layerRecord);
391 m_layerRecords.push_back(pLayerRecord);
392 }
393 }
394
395 bool MatrixFile::Save(std::ostream& os)
396 {
397 for (const auto& stepRecord : m_stepRecords)
398 {
399 os << StepRecord::RECORD_TOKEN << " " << Constants::ARRAY_RECORD_OPEN_TOKEN << std::endl;
400
401 os << '\t' << StepRecord::COLUMN_KEY << "=" << stepRecord->column << std::endl;
402 os << '\t' << StepRecord::NAME_KEY << "=" << stepRecord->name << std::endl;
403 os << '\t' << StepRecord::ID_KEY << "=" << stepRecord->id << std::endl;
404
405 os << Constants::ARRAY_RECORD_CLOSE_TOKEN << std::endl;
406 os << std::endl;
407 }
408
409 for (const auto& layerRecord : m_layerRecords)
410 {
411 os << LayerRecord::RECORD_TOKEN << " " << Constants::ARRAY_RECORD_OPEN_TOKEN << std::endl;
412
413 os << '\t' << LayerRecord::ROW_KEY << "=" << layerRecord->row << std::endl;
414 os << '\t' << LayerRecord::CONTEXT_KEY << "=" << LayerRecord::contextMap.getValue(layerRecord->context) << std::endl;
415 os << '\t' << LayerRecord::TYPE_KEY << "=" << LayerRecord::typeMap.getValue(layerRecord->type) << std::endl;
416 os << '\t' << LayerRecord::NAME_KEY << "=" << layerRecord->name << std::endl;
417 os << '\t' << LayerRecord::POLARITY_KEY << "=" << LayerRecord::polarityMap.getValue(layerRecord->polarity) << std::endl;
418 os << '\t' << LayerRecord::FORM_KEY << "=" << LayerRecord::formMap.getValue(layerRecord->form) << std::endl;
419 os << '\t' << LayerRecord::DIELECTRIC_TYPE_KEY << "=" << LayerRecord::dielectricTypeMap.getValue(layerRecord->dielectricType) << std::endl;
420 os << '\t' << LayerRecord::DIELECTRIC_NAME_KEY << "=" << layerRecord->dielectricName << std::endl;
421 os << '\t' << LayerRecord::CU_TOP_KEY << "=";
422 if (layerRecord->cuTop != (unsigned int)-1)
423 {
424 os << layerRecord->cuTop;
425 }
426 os << std::endl;
427 os << '\t' << LayerRecord::CU_BOTTOM_KEY << "=";
428 if (layerRecord->cuBottom != (unsigned int)-1)
429 {
430 os << layerRecord->cuBottom;
431 }
432 os << std::endl;
433 os << '\t' << LayerRecord::REF_KEY << "=";
434 if (layerRecord->ref != (unsigned int)-1)
435 {
436 os << layerRecord->ref;
437 }
438 os << std::endl;
439 os << '\t' << LayerRecord::START_NAME_KEY << "=" << layerRecord->startName << std::endl;
440 os << '\t' << LayerRecord::END_NAME_KEY << "=" << layerRecord->endName << std::endl;
441 os << '\t' << LayerRecord::OLD_NAME_KEY << "=" << layerRecord->oldName << std::endl;
442 os << '\t' << LayerRecord::ADD_TYPE_KEY << "=" << layerRecord->addType << std::endl;
443 os << '\t' << LayerRecord::COLOR_KEY << "=" << layerRecord->color.to_string() << std::endl;
444 os << '\t' << LayerRecord::ID_KEY << "=" << layerRecord->id << std::endl;
445
446 os << Constants::ARRAY_RECORD_CLOSE_TOKEN << std::endl;
447 os << std::endl;
448 }
449
450 return true;
451 }
452
453 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::StepRecord> Odb::Lib::FileModel::Design::MatrixFile::StepRecord::to_protobuf() const
454 {
455 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::StepRecord> pStepRecordMessage(new Odb::Lib::Protobuf::MatrixFile::StepRecord);
456 pStepRecordMessage->set_column(column);
457 pStepRecordMessage->set_name(name);
458 pStepRecordMessage->set_id(id);
459 return pStepRecordMessage;
460 }
461
462 void Odb::Lib::FileModel::Design::MatrixFile::StepRecord::from_protobuf(const Odb::Lib::Protobuf::MatrixFile::StepRecord& message)
463 {
464 column = message.column();
465 name = message.name();
466 id = message.id();
467 }
468
469 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::LayerRecord> Odb::Lib::FileModel::Design::MatrixFile::LayerRecord::to_protobuf() const
470 {
471 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::LayerRecord> pLayerRecordMessage(new Odb::Lib::Protobuf::MatrixFile::LayerRecord);
472 pLayerRecordMessage->set_addtype(addType);
473 pLayerRecordMessage->set_context(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::Context>(context));
474 pLayerRecordMessage->set_cubottom(cuBottom);
475 pLayerRecordMessage->set_cutop(cuTop);
476 pLayerRecordMessage->set_dielectricname(dielectricName);
477 pLayerRecordMessage->set_dielectrictype(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::DielectricType>(dielectricType));
478 pLayerRecordMessage->set_endname(endName);
479 pLayerRecordMessage->set_form(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::Form>(form));
480 pLayerRecordMessage->set_id(id);
481 pLayerRecordMessage->set_name(name);
482 pLayerRecordMessage->set_oldname(oldName);
483 pLayerRecordMessage->set_polarity(static_cast<Odb::Lib::Protobuf::Polarity>(polarity));
484 pLayerRecordMessage->set_ref(ref);
485 pLayerRecordMessage->set_row(row);
486 pLayerRecordMessage->set_startname(startName);
487 pLayerRecordMessage->set_type(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::Type>(type));
488 pLayerRecordMessage->mutable_color()->set_red(color.red);
489 pLayerRecordMessage->mutable_color()->set_green(color.green);
490 pLayerRecordMessage->mutable_color()->set_blue(color.blue);
491 pLayerRecordMessage->mutable_color()->set_nopreference(color.noPreference);
492
493
494 return pLayerRecordMessage;
495 }
496
497 void Odb::Lib::FileModel::Design::MatrixFile::LayerRecord::from_protobuf(const Odb::Lib::Protobuf::MatrixFile::LayerRecord& message)
498 {
499 addType = message.addtype();
500 context = static_cast<Context>(message.context());
501 cuBottom = message.cubottom();
502 cuTop = message.cutop();
503 dielectricName = message.dielectricname();
504 dielectricType = static_cast<DielectricType>(message.dielectrictype());
505 endName = message.endname();
506 form = static_cast<Form>(message.form());
507 id = message.id();
508 name = message.name();
509 oldName = message.oldname();
510 polarity = static_cast<Polarity>(message.polarity());
511 ref = message.ref();
512 row = message.row();
513 startName = message.startname();
514 type = static_cast<Type>(message.type());
515 color.red = message.color().red();
516 color.green = message.color().green();
517 color.blue = message.color().blue();
518 color.noPreference = message.color().nopreference();
519 }
520}