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