Skip to content

Commit 1302376

Browse files
committed
Add separate BddFormatter
1 parent 6fd65f6 commit 1302376

3 files changed

Lines changed: 288 additions & 104 deletions

File tree

smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/logic/bdd/Bdd.java

Lines changed: 71 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
*/
55
package software.amazon.smithy.rulesengine.logic.bdd;
66

7+
import java.io.ByteArrayOutputStream;
8+
import java.io.IOException;
9+
import java.io.OutputStreamWriter;
10+
import java.io.Writer;
11+
import java.nio.charset.StandardCharsets;
712
import java.util.Arrays;
813
import java.util.List;
914
import java.util.Objects;
@@ -247,107 +252,81 @@ public int hashCode() {
247252

248253
@Override
249254
public String toString() {
250-
return toString(new StringBuilder()).toString();
251-
}
252-
253-
/**
254-
* Appends a string representation to the given StringBuilder.
255-
*
256-
* @param sb the StringBuilder to append to
257-
* @return the given string builder.
258-
*/
259-
public StringBuilder toString(StringBuilder sb) {
260-
// Calculate max width needed for first column identifiers
261-
int maxConditionIdx = conditions.size() - 1;
262-
int maxResultIdx = results.size() - 1;
263-
264-
// Width needed for "C" + maxConditionIdx or "R" + maxResultIdx
265-
int conditionWidth = maxConditionIdx >= 0 ? String.valueOf(maxConditionIdx).length() + 1 : 2;
266-
int resultWidth = maxResultIdx >= 0 ? String.valueOf(maxResultIdx).length() + 1 : 2;
267-
int varWidth = Math.max(conditionWidth, resultWidth);
268-
269-
sb.append("Bdd{\n");
270-
271-
// Conditions
272-
sb.append(" conditions (").append(getConditionCount()).append("):\n");
273-
for (int i = 0; i < conditions.size(); i++) {
274-
sb.append(String.format(" %" + varWidth + "s: %s%n", "C" + i, conditions.get(i)));
275-
}
276-
277-
// Results
278-
sb.append(" results (").append(results.size()).append("):\n");
279-
for (int i = 0; i < results.size(); i++) {
280-
sb.append(String.format(" %" + varWidth + "s: ", "R" + i));
281-
appendResult(sb, results.get(i));
282-
sb.append("\n");
283-
}
255+
try {
256+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
257+
Writer writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8);
258+
259+
// Calculate width for condition/result indices
260+
int maxConditionIdx = conditions.size() - 1;
261+
int maxResultIdx = results.size() - 1;
262+
int conditionWidth = maxConditionIdx >= 0 ? String.valueOf(maxConditionIdx).length() + 1 : 2;
263+
int resultWidth = maxResultIdx >= 0 ? String.valueOf(maxResultIdx).length() + 1 : 2;
264+
int varWidth = Math.max(conditionWidth, resultWidth);
265+
266+
writer.write("Bdd{\n");
267+
268+
// Write conditions
269+
writer.write(" conditions (");
270+
writer.write(String.valueOf(getConditionCount()));
271+
writer.write("):\n");
272+
for (int i = 0; i < conditions.size(); i++) {
273+
writer.write(String.format(" %" + varWidth + "s: %s%n", "C" + i, conditions.get(i)));
274+
}
284275

285-
// Root
286-
sb.append(" root: ").append(formatReference(rootRef)).append("\n");
287-
288-
// Nodes
289-
sb.append(" nodes (").append(nodes.length).append("):\n");
290-
291-
// Calculate width needed for node indices
292-
int indexWidth = String.valueOf(nodes.length - 1).length();
293-
294-
for (int i = 0; i < nodes.length; i++) {
295-
sb.append(String.format(" %" + indexWidth + "d: ", i));
296-
if (i == 0) {
297-
sb.append("terminal");
298-
} else {
299-
int[] node = nodes[i];
300-
int varIdx = node[0];
301-
sb.append("[");
302-
303-
// Use the calculated width for variable/result references
304-
if (varIdx < conditions.size()) {
305-
sb.append(String.format("%" + varWidth + "s", "C" + varIdx));
306-
} else {
307-
sb.append(String.format("%" + varWidth + "s", "R" + (varIdx - conditions.size())));
308-
}
309-
310-
// Format the references with consistent spacing
311-
sb.append(", ")
312-
.append(String.format("%6s", formatReference(node[1])))
313-
.append(", ")
314-
.append(String.format("%6s", formatReference(node[2])))
315-
.append("]");
276+
// Write results
277+
writer.write(" results (");
278+
writer.write(String.valueOf(results.size()));
279+
writer.write("):\n");
280+
for (int i = 0; i < results.size(); i++) {
281+
writer.write(String.format(" %" + varWidth + "s: ", "R" + i));
282+
appendResult(writer, results.get(i));
283+
writer.write("\n");
316284
}
317-
sb.append("\n");
318-
}
319285

320-
sb.append("}");
321-
return sb;
286+
// Write root
287+
writer.write(" root: ");
288+
writer.write(BddFormatter.formatReference(rootRef));
289+
writer.write("\n");
290+
291+
// Write nodes header
292+
writer.write(" nodes (");
293+
writer.write(String.valueOf(nodes.length));
294+
writer.write("):\n");
295+
296+
writer.flush();
297+
298+
// Use BddFormatter for nodes - no need to strip anything since we control the indent
299+
BddFormatter.builder()
300+
.writer(writer)
301+
.nodes(nodes)
302+
.rootRef(rootRef)
303+
.conditionCount(conditions.size())
304+
.resultCount(results.size())
305+
.indent(" ")
306+
.build()
307+
.format();
308+
309+
writer.write("}");
310+
writer.flush();
311+
312+
return baos.toString(StandardCharsets.UTF_8.name());
313+
} catch (IOException e) {
314+
// Should never happen with ByteArrayOutputStream
315+
throw new RuntimeException("Failed to format BDD", e);
316+
}
322317
}
323318

324-
private void appendResult(StringBuilder sb, Rule result) {
319+
private void appendResult(Writer writer, Rule result) throws IOException {
325320
if (result == null) {
326-
sb.append("(no match)");
321+
writer.write("(no match)");
327322
} else if (result instanceof EndpointRule) {
328-
sb.append("Endpoint: ").append(((EndpointRule) result).getEndpoint().getUrl());
323+
writer.write("Endpoint: ");
324+
writer.write(((EndpointRule) result).getEndpoint().getUrl().toString());
329325
} else if (result instanceof ErrorRule) {
330-
sb.append("Error: ").append(((ErrorRule) result).getError());
331-
} else {
332-
sb.append(result.getClass().getSimpleName());
333-
}
334-
}
335-
336-
private String formatReference(int ref) {
337-
if (ref == 0) {
338-
return "INVALID";
339-
} else if (ref == 1) {
340-
return "TRUE";
341-
} else if (ref == -1) {
342-
return "FALSE";
343-
} else if (ref >= Bdd.RESULT_OFFSET) {
344-
// This is a result reference
345-
int resultIdx = ref - Bdd.RESULT_OFFSET;
346-
return "R" + resultIdx;
347-
} else if (ref < 0) {
348-
return "!" + (Math.abs(ref) - 1);
326+
writer.write("Error: ");
327+
writer.write(((ErrorRule) result).getError().toString());
349328
} else {
350-
return String.valueOf(ref - 1);
329+
writer.write(result.getClass().getSimpleName());
351330
}
352331
}
353332

0 commit comments

Comments
 (0)