Skip to content

Gwf to scs improve#494

Draft
RivaKing wants to merge 4 commits into
ostis-ai:mainfrom
RivaKing:gwf-to-scs-improve
Draft

Gwf to scs improve#494
RivaKing wants to merge 4 commits into
ostis-ai:mainfrom
RivaKing:gwf-to-scs-improve

Conversation

@RivaKing

@RivaKing RivaKing commented May 14, 2025

Copy link
Copy Markdown

Important

Improves GWF-to-SCs translation with new command-line options and enhanced SCs file output handling in sc_builder_runner.cpp and sc_scs_writer.cpp.

  • Behavior:
    • Added --gwf-to-scs and --gwf-output options in sc_builder_runner.cpp for translating GWF files to SCs.
    • Enhanced SCs file output in SCsWriter::Write() in sc_scs_writer.cpp to handle nodes, arcs, and contours more effectively.
  • Functions:
    • PrintHelpMessage() in sc_builder_runner.cpp updated with new options for GWF-to-SCs translation.
    • SCsWriter::Write() refactored to improve node and arc processing, including handling of SCgLinks and image content.
    • Added SCsWriter::CollectNodes() to recursively gather nodes, including those in contours.
  • Misc:
    • Included sc_scg_to_scs_types_converter.hpp in sc_scs_writer.cpp for type conversion.
    • Updated SCsWriter::SCgIdentifierCorrector methods for identifier correction.

This description was created by Ellipsis for e7e2424. You can customize this summary. It will automatically update as commits are pushed.

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Changes requested ❌

Reviewed everything up to e7e2424 in 2 minutes and 38 seconds. Click for details.
  • Reviewed 709 lines of code in 3 files
  • Skipped 0 files when reviewing.
  • Skipped posting 1 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. sc-tools/sc-builder/src/sc_scs_writer.cpp:242
  • Draft comment:
    The nested loop for attribute arc lookup could be optimized for performance if the element set is large.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% While the loop could potentially be optimized by using a different data structure, there's no evidence in the code that this is a performance bottleneck. The code already has an early break and the operation only happens for complex arcs. Without profiling data or clear evidence of performance issues, this seems like premature optimization. The comment could be valid if this code processes very large graphs where performance is critical. The current implementation is O(n) for each complex arc. However, the code appears to be part of a file writer/serializer which is likely not in a performance-critical path. The current implementation prioritizes readability and maintainability. The comment should be deleted as it suggests optimization without clear evidence of need, making it speculative rather than actionable.

Workflow ID: wflow_AzBo1HFyETNEoagk

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

std::ofstream output(outputFile, std::ios::binary);
if (!output.is_open())
{
std::cout << "Error: Cannot open output file `" << outputFile << "`.\n";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using std::cerr for error messages instead of std::cout.

Suggested change
std::cout << "Error: Cannot open output file `" << outputFile << "`.\n";
std::cerr << "Error: Cannot open output file `" << outputFile << "`.\n";

auto link = std::dynamic_pointer_cast<SCgLink>(node);
if (link && link->GetContentType() != NO_CONTENT)
{
std::string contentTypeStr = link->GetContentType();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate contentTypeStr before converting with std::stoi to avoid exceptions from malformed data.

}
else if (contentType == 4) // IMAGE
{
std::string fileName = link->GetFileName();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sanitize fileName to prevent potential directory traversal issues when constructing file paths.

Suggested change
std::string fileName = link->GetFileName();
std::string fileName = std::filesystem::path(link->GetFileName()).filename().string();


if (!attrSourceId.empty())
{
std::string connectorSymbol;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider refactoring the connector printing logic into a helper function to reduce code duplication.

}
}

void SCsWriter::Write(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider splitting the lengthy Write() function into smaller helper functions to improve readability and maintainability.

@NikitaZotov
NikitaZotov marked this pull request as draft July 14, 2025 14:59
Comment on lines +154 to +155
std::string contentTypeStr = link->GetContentType();
int contentType = std::stoi(contentTypeStr);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Edge Case: std::stoi on content type can throw and crash the tool

int contentType = std::stoi(link->GetContentType()); throws std::invalid_argument/std::out_of_range if the GWF content-type string is non-numeric or malformed. RunBuilder's function-try-block only catches utils::ScException, so this standard exception propagates uncaught and terminates the process. Validate the string or wrap the conversion and throw an ScException on failure.

Guard std::stoi so malformed content types raise an ScException instead of crashing.:

std::string contentTypeStr = link->GetContentType();
int contentType = 0;
try
{
  contentType = std::stoi(contentTypeStr);
}
catch (std::exception const &)
{
  SC_THROW_EXCEPTION(
      utils::ExceptionInvalidParams,
      "SCsWriter::Write: invalid link content type `" << contentTypeStr << "`.");
}
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +234 to +248
for (auto const & [id, element] : elements)
{
size_t connectorsWrittenOnPreviousIteration = dependedConnectors.size();
while (connectorsWrittenOnPreviousIteration != 0)
if (element->GetTag() == ARC || element->GetTag() == PAIR)
{
connectorsWrittenOnPreviousIteration = 0;
for (auto dependedConnector = dependedConnectors.cbegin(); dependedConnector != dependedConnectors.cend();)
if (writtenElements.count(element))
continue;
if (attributeArcs.count(element))
continue;
writtenElements.insert(element);

auto connector = std::dynamic_pointer_cast<SCgConnector>(element);
std::string sourceId = connector->GetSource()->GetIdentifier();
std::string targetId = connector->GetTarget()->GetIdentifier();
if (sourceId.empty())
sourceId = NODE + UNDERSCORE + connector->GetSource()->GetId();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Performance: O(n^2) inner scan to find attribute-arc source

For every complex arc, the code rescans the entire elements map to locate the incoming attribute arc (lines 255-268), making arc writing O(arcs * elements). On large contours/graphs this is a needless hot-path cost. Precompute a map from target element to its incoming attribute arc in the Step-2 pass and look it up in O(1).

Build a target->attribute-arc index once instead of rescanning per complex arc.:

// Step 2: also record, for each complex arc, its incoming attribute arc
std::unordered_map<SCgElementPtr, SCgElementPtr> attrArcByTarget;
// ... when inserting: attrArcByTarget[target] = element;

// Step 3: replace the inner for-loop scan with:
auto attrIt = attrArcByTarget.find(element);
if (attrIt != attrArcByTarget.end()) { /* use attrIt->second's source */ }
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +254 to +268
std::string attrSourceId;
for (auto const & [incomingId, incomingElement] : elements)
{
auto const & scsElement = SCsElementFactory::CreateSCsElementForSCgElement(*dependedConnector);
scsElement->ConvertFromSCgElement(*dependedConnector);
scsElement->Dump(filePath, buffer, depth, writtenElements);
writtenElements.insert(*dependedConnector);
++connectorsWrittenOnPreviousIteration;
dependedConnector = dependedConnectors.erase(dependedConnector);
if (incomingElement->GetTag() == ARC || incomingElement->GetTag() == PAIR)
{
auto incConnector = std::dynamic_pointer_cast<SCgConnector>(incomingElement);
if (incConnector->GetTarget() == element)
{
attrSourceId = incConnector->GetSource()->GetIdentifier();
if (attrSourceId.empty())
attrSourceId = NODE + UNDERSCORE + incConnector->GetSource()->GetId();
break;
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Edge Case: Only first attribute of a complex arc is emitted

The lookup loop breaks at the first incoming attribute arc, so if a single arc carries multiple attribute arcs (e.g. several role relations), all but one are silently dropped from the generated SCs, losing semantic information. Iterate all incoming attribute arcs and emit each attribute rather than stopping at the first match.

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 0 resolved / 3 findings

Adds GWF-to-SCs translation capabilities with updated command-line options, but std::stoi usage lacks safety, the attribute-arc lookup performs redundant O(n^2) scans, and the current implementation fails to process multiple attributes per arc.

⚠️ Edge Case: std::stoi on content type can throw and crash the tool

📄 sc-tools/sc-builder/src/sc_scs_writer.cpp:154-155 📄 sc-tools/sc-builder/src/sc_builder_runner.cpp:211-215

int contentType = std::stoi(link->GetContentType()); throws std::invalid_argument/std::out_of_range if the GWF content-type string is non-numeric or malformed. RunBuilder's function-try-block only catches utils::ScException, so this standard exception propagates uncaught and terminates the process. Validate the string or wrap the conversion and throw an ScException on failure.

Guard std::stoi so malformed content types raise an ScException instead of crashing.
std::string contentTypeStr = link->GetContentType();
int contentType = 0;
try
{
  contentType = std::stoi(contentTypeStr);
}
catch (std::exception const &)
{
  SC_THROW_EXCEPTION(
      utils::ExceptionInvalidParams,
      "SCsWriter::Write: invalid link content type `" << contentTypeStr << "`.");
}
💡 Performance: O(n^2) inner scan to find attribute-arc source

📄 sc-tools/sc-builder/src/sc_scs_writer.cpp:234-248

For every complex arc, the code rescans the entire elements map to locate the incoming attribute arc (lines 255-268), making arc writing O(arcs * elements). On large contours/graphs this is a needless hot-path cost. Precompute a map from target element to its incoming attribute arc in the Step-2 pass and look it up in O(1).

Build a target->attribute-arc index once instead of rescanning per complex arc.
// Step 2: also record, for each complex arc, its incoming attribute arc
std::unordered_map<SCgElementPtr, SCgElementPtr> attrArcByTarget;
// ... when inserting: attrArcByTarget[target] = element;

// Step 3: replace the inner for-loop scan with:
auto attrIt = attrArcByTarget.find(element);
if (attrIt != attrArcByTarget.end()) { /* use attrIt->second's source */ }
💡 Edge Case: Only first attribute of a complex arc is emitted

📄 sc-tools/sc-builder/src/sc_scs_writer.cpp:254-268

The lookup loop breaks at the first incoming attribute arc, so if a single arc carries multiple attribute arcs (e.g. several role relations), all but one are silently dropped from the generated SCs, losing semantic information. Iterate all incoming attribute arcs and emit each attribute rather than stopping at the first match.

🤖 Prompt for agents
Code Review: Adds GWF-to-SCs translation capabilities with updated command-line options, but `std::stoi` usage lacks safety, the attribute-arc lookup performs redundant O(n^2) scans, and the current implementation fails to process multiple attributes per arc.

1. ⚠️ Edge Case: std::stoi on content type can throw and crash the tool
   Files: sc-tools/sc-builder/src/sc_scs_writer.cpp:154-155, sc-tools/sc-builder/src/sc_builder_runner.cpp:211-215

   `int contentType = std::stoi(link->GetContentType());` throws `std::invalid_argument`/`std::out_of_range` if the GWF content-type string is non-numeric or malformed. RunBuilder's function-try-block only catches `utils::ScException`, so this standard exception propagates uncaught and terminates the process. Validate the string or wrap the conversion and throw an ScException on failure.

   Fix (Guard std::stoi so malformed content types raise an ScException instead of crashing.):
   std::string contentTypeStr = link->GetContentType();
   int contentType = 0;
   try
   {
     contentType = std::stoi(contentTypeStr);
   }
   catch (std::exception const &)
   {
     SC_THROW_EXCEPTION(
         utils::ExceptionInvalidParams,
         "SCsWriter::Write: invalid link content type `" << contentTypeStr << "`.");
   }

2. 💡 Performance: O(n^2) inner scan to find attribute-arc source
   Files: sc-tools/sc-builder/src/sc_scs_writer.cpp:234-248

   For every complex arc, the code rescans the entire `elements` map to locate the incoming attribute arc (lines 255-268), making arc writing O(arcs * elements). On large contours/graphs this is a needless hot-path cost. Precompute a map from target element to its incoming attribute arc in the Step-2 pass and look it up in O(1).

   Fix (Build a target->attribute-arc index once instead of rescanning per complex arc.):
   // Step 2: also record, for each complex arc, its incoming attribute arc
   std::unordered_map<SCgElementPtr, SCgElementPtr> attrArcByTarget;
   // ... when inserting: attrArcByTarget[target] = element;
   
   // Step 3: replace the inner for-loop scan with:
   auto attrIt = attrArcByTarget.find(element);
   if (attrIt != attrArcByTarget.end()) { /* use attrIt->second's source */ }

3. 💡 Edge Case: Only first attribute of a complex arc is emitted
   Files: sc-tools/sc-builder/src/sc_scs_writer.cpp:254-268

   The lookup loop `break`s at the first incoming attribute arc, so if a single arc carries multiple attribute arcs (e.g. several role relations), all but one are silently dropped from the generated SCs, losing semantic information. Iterate all incoming attribute arcs and emit each attribute rather than stopping at the first match.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants