diff options
Diffstat (limited to 'src/visualizer')
| -rw-r--r-- | src/visualizer/grid.c | 146 | ||||
| -rw-r--r-- | src/visualizer/grid.h | 10 | ||||
| -rw-r--r-- | src/visualizer/horizontal_cli.c | 600 | ||||
| -rw-r--r-- | src/visualizer/vertical_cli.c | 536 |
4 files changed, 646 insertions, 646 deletions
diff --git a/src/visualizer/grid.c b/src/visualizer/grid.c index 32ade1b..29d1981 100644 --- a/src/visualizer/grid.c +++ b/src/visualizer/grid.c @@ -6,129 +6,129 @@ static size_t glyph_bytes(unsigned char lead) { - if (lead < 0x80) - return 1; - if ((lead >> 5) == 0x6) - return 2; - if ((lead >> 4) == 0xE) - return 3; - if ((lead >> 3) == 0x1E) - return 4; + if (lead < 0x80) + return 1; + if ((lead >> 5) == 0x6) + return 2; + if ((lead >> 4) == 0xE) + return 3; + if ((lead >> 3) == 0x1E) + return 4; - return 1; + return 1; } size_t psi_utf8_count(const char* s) { - size_t count = 0; - while (*s) - { - s += glyph_bytes((unsigned char)*s); - count++; - } + size_t count = 0; + while (*s) + { + s += glyph_bytes((unsigned char)*s); + count++; + } - return count; + return count; } struct PsiStringBuilder psi_new_string_builder(void) { - return (struct PsiStringBuilder){ - NULL, - 0, - 0, - }; + return (struct PsiStringBuilder){ + NULL, + 0, + 0, + }; } void psi_string_builder_append(struct PsiStringBuilder* sb, const char* s) { - size_t n = strlen(s); - if (sb->len + n + 1 > sb->cap) - { - size_t new_cap = sb->cap == 0 ? 256 : sb->cap * 2; - while (new_cap < sb->len + n + 1) - new_cap *= 2; + size_t n = strlen(s); + if (sb->len + n + 1 > sb->cap) + { + size_t new_cap = sb->cap == 0 ? 256 : sb->cap * 2; + while (new_cap < sb->len + n + 1) + new_cap *= 2; - sb->data = realloc(sb->data, new_cap); - assert(sb->data != NULL); - sb->cap = new_cap; - } + sb->data = realloc(sb->data, new_cap); + assert(sb->data != NULL); + sb->cap = new_cap; + } - memcpy(sb->data + sb->len, s, n + 1); - sb->len += n; + memcpy(sb->data + sb->len, s, n + 1); + sb->len += n; } char* psi_string_builder_finish(struct PsiStringBuilder* sb) { - if (sb->data == NULL) - psi_string_builder_append(sb, ""); + if (sb->data == NULL) + psi_string_builder_append(sb, ""); - return sb->data; + return sb->data; } struct PsiGlyphRow psi_new_glyph_row(size_t width) { - char (*cells)[5] = malloc(width * sizeof(*cells)); - assert(cells != NULL || width == 0); + char (*cells)[5] = malloc(width * sizeof(*cells)); + assert(cells != NULL || width == 0); - for (size_t i = 0; i < width; i++) - memcpy(cells[i], " ", 2); + for (size_t i = 0; i < width; i++) + memcpy(cells[i], " ", 2); - return (struct PsiGlyphRow){ - cells, - width, - }; + return (struct PsiGlyphRow){ + cells, + width, + }; } void psi_free_glyph_row(struct PsiGlyphRow* row) { - free(row->cells); - row->cells = NULL; - row->width = 0; + free(row->cells); + row->cells = NULL; + row->width = 0; } void psi_glyph_row_set(struct PsiGlyphRow* row, size_t index, const char* glyph) { - if (index >= row->width) - return; + if (index >= row->width) + return; - size_t n = glyph_bytes((unsigned char)glyph[0]); - memcpy(row->cells[index], glyph, n); - row->cells[index][n] = '\0'; + size_t n = glyph_bytes((unsigned char)glyph[0]); + memcpy(row->cells[index], glyph, n); + row->cells[index][n] = '\0'; } size_t psi_glyph_row_place(struct PsiGlyphRow* row, size_t start, const char* utf8) { - size_t count = 0; - const char* p = utf8; + size_t count = 0; + const char* p = utf8; - while (*p) - { - size_t n = glyph_bytes((unsigned char)*p); - size_t index = start + count; - if (index < row->width) - { - memcpy(row->cells[index], p, n); - row->cells[index][n] = '\0'; - } + while (*p) + { + size_t n = glyph_bytes((unsigned char)*p); + size_t index = start + count; + if (index < row->width) + { + memcpy(row->cells[index], p, n); + row->cells[index][n] = '\0'; + } - p += n; - count++; - } + p += n; + count++; + } - return count; + return count; } void psi_glyph_row_fill_space(struct PsiGlyphRow* row, size_t from, size_t to, const char* glyph) { - for (size_t i = from; i < to && i < row->width; i++) - if (strcmp(row->cells[i], " ") == 0) - psi_glyph_row_set(row, i, glyph); + for (size_t i = from; i < to && i < row->width; i++) + if (strcmp(row->cells[i], " ") == 0) + psi_glyph_row_set(row, i, glyph); } void psi_glyph_row_render(struct PsiGlyphRow row, struct PsiStringBuilder* sb) { - for (size_t i = 0; i < row.width; i++) - psi_string_builder_append(sb, row.cells[i]); + for (size_t i = 0; i < row.width; i++) + psi_string_builder_append(sb, row.cells[i]); - psi_string_builder_append(sb, "\n"); + psi_string_builder_append(sb, "\n"); } diff --git a/src/visualizer/grid.h b/src/visualizer/grid.h index 9353433..f02941a 100644 --- a/src/visualizer/grid.h +++ b/src/visualizer/grid.h @@ -4,9 +4,9 @@ struct PsiStringBuilder { - char* data; - size_t len; - size_t cap; + char* data; + size_t len; + size_t cap; }; struct PsiStringBuilder psi_new_string_builder(void); @@ -15,8 +15,8 @@ char* psi_string_builder_finish(struct PsiStringBuilder* sb); struct PsiGlyphRow { - char (*cells)[5]; - size_t width; + char (*cells)[5]; + size_t width; }; struct PsiGlyphRow psi_new_glyph_row(size_t width); diff --git a/src/visualizer/horizontal_cli.c b/src/visualizer/horizontal_cli.c index 56a2e00..9f7620e 100644 --- a/src/visualizer/horizontal_cli.c +++ b/src/visualizer/horizontal_cli.c @@ -10,344 +10,344 @@ static void append_repeat(struct PsiStringBuilder* sb, const char* glyph, size_t n) { - for (size_t i = 0; i < n; i++) - psi_string_builder_append(sb, glyph); + for (size_t i = 0; i < n; i++) + psi_string_builder_append(sb, glyph); } static bool is_single_target(enum PsiGateKind kind) { - switch (kind) - { - case PSI_GATE_H: - case PSI_GATE_X: - case PSI_GATE_Y: - case PSI_GATE_Z: - case PSI_GATE_S: - case PSI_GATE_T: - case PSI_GATE_SDG: - case PSI_GATE_TDG: - case PSI_GATE_SX: - case PSI_GATE_SXDG: - case PSI_GATE_RX: - case PSI_GATE_RY: - case PSI_GATE_RZ: - case PSI_GATE_P: - case PSI_GATE_U1: - case PSI_GATE_U2: - case PSI_GATE_U3: return true; - default: return false; - } + switch (kind) + { + case PSI_GATE_H: + case PSI_GATE_X: + case PSI_GATE_Y: + case PSI_GATE_Z: + case PSI_GATE_S: + case PSI_GATE_T: + case PSI_GATE_SDG: + case PSI_GATE_TDG: + case PSI_GATE_SX: + case PSI_GATE_SXDG: + case PSI_GATE_RX: + case PSI_GATE_RY: + case PSI_GATE_RZ: + case PSI_GATE_P: + case PSI_GATE_U1: + case PSI_GATE_U2: + case PSI_GATE_U3: return true; + default: return false; + } } static void single_label(struct PsiGateOp op, char* out, size_t cap) { - switch (op.kind) - { - case PSI_GATE_H: snprintf(out, cap, "[H]"); break; - case PSI_GATE_X: snprintf(out, cap, "[X]"); break; - case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break; - case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break; - case PSI_GATE_S: snprintf(out, cap, "[S]"); break; - case PSI_GATE_T: snprintf(out, cap, "[T]"); break; - case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break; - case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break; - case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break; - case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break; - case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break; - case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break; - case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break; - case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break; - case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break; - case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break; - case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break; - default: snprintf(out, cap, "[?]"); break; - } + switch (op.kind) + { + case PSI_GATE_H: snprintf(out, cap, "[H]"); break; + case PSI_GATE_X: snprintf(out, cap, "[X]"); break; + case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break; + case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break; + case PSI_GATE_S: snprintf(out, cap, "[S]"); break; + case PSI_GATE_T: snprintf(out, cap, "[T]"); break; + case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break; + case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break; + case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break; + case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break; + case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break; + case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break; + case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break; + case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break; + case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break; + case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break; + case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break; + default: snprintf(out, cap, "[?]"); break; + } } static void controlled_label(struct PsiGateOp op, char* out, size_t cap) { - switch (op.kind) - { - case PSI_GATE_CRX: snprintf(out, cap, "[CRx(%.2f)]", op.params[0]); break; - case PSI_GATE_CRY: snprintf(out, cap, "[CRy(%.2f)]", op.params[0]); break; - case PSI_GATE_CRZ: snprintf(out, cap, "[CRz(%.2f)]", op.params[0]); break; - case PSI_GATE_CP: snprintf(out, cap, "[CP(%.2f)]", op.params[0]); break; - default: snprintf(out, cap, "[?]"); break; - } + switch (op.kind) + { + case PSI_GATE_CRX: snprintf(out, cap, "[CRx(%.2f)]", op.params[0]); break; + case PSI_GATE_CRY: snprintf(out, cap, "[CRy(%.2f)]", op.params[0]); break; + case PSI_GATE_CRZ: snprintf(out, cap, "[CRz(%.2f)]", op.params[0]); break; + case PSI_GATE_CP: snprintf(out, cap, "[CP(%.2f)]", op.params[0]); break; + default: snprintf(out, cap, "[?]"); break; + } } static bool is_param_controlled(enum PsiGateKind kind) { - switch (kind) - { - case PSI_GATE_CRX: - case PSI_GATE_CRY: - case PSI_GATE_CRZ: - case PSI_GATE_CP: return true; - default: return false; - } + switch (kind) + { + case PSI_GATE_CRX: + case PSI_GATE_CRY: + case PSI_GATE_CRZ: + case PSI_GATE_CP: return true; + default: return false; + } } char* psi_render_circuit_horizontal(const struct PsiQuantumCircuit* circuit) { - size_t nq = circuit->num_qubits; - size_t nc = circuit->num_classical; + size_t nq = circuit->num_qubits; + size_t nc = circuit->num_classical; - struct PsiStringBuilder* q = nq > 0 ? malloc(nq * sizeof(struct PsiStringBuilder)) : NULL; - struct PsiStringBuilder* c = nc > 0 ? malloc(nc * sizeof(struct PsiStringBuilder)) : NULL; - assert(q != NULL || nq == 0); - assert(c != NULL || nc == 0); + struct PsiStringBuilder* q = nq > 0 ? malloc(nq * sizeof(struct PsiStringBuilder)) : NULL; + struct PsiStringBuilder* c = nc > 0 ? malloc(nc * sizeof(struct PsiStringBuilder)) : NULL; + assert(q != NULL || nq == 0); + assert(c != NULL || nc == 0); - size_t max_label = 3; - for (size_t i = 0; i < nq; i++) - { - char lbl[16]; - snprintf(lbl, sizeof lbl, "q%zu: ", i); - if (strlen(lbl) > max_label) - max_label = strlen(lbl); - } - for (size_t i = 0; i < nc; i++) - { - char lbl[16]; - snprintf(lbl, sizeof lbl, "c%zu: ", i); - if (strlen(lbl) > max_label) - max_label = strlen(lbl); - } + size_t max_label = 3; + for (size_t i = 0; i < nq; i++) + { + char lbl[16]; + snprintf(lbl, sizeof lbl, "q%zu: ", i); + if (strlen(lbl) > max_label) + max_label = strlen(lbl); + } + for (size_t i = 0; i < nc; i++) + { + char lbl[16]; + snprintf(lbl, sizeof lbl, "c%zu: ", i); + if (strlen(lbl) > max_label) + max_label = strlen(lbl); + } - for (size_t i = 0; i < nq; i++) - { - q[i] = psi_new_string_builder(); - char lbl[16]; - snprintf(lbl, sizeof lbl, "q%zu: ", i); - append_repeat(&q[i], " ", max_label - strlen(lbl)); - psi_string_builder_append(&q[i], lbl); - } - for (size_t i = 0; i < nc; i++) - { - c[i] = psi_new_string_builder(); - char lbl[16]; - snprintf(lbl, sizeof lbl, "c%zu: ", i); - append_repeat(&c[i], " ", max_label - strlen(lbl)); - psi_string_builder_append(&c[i], lbl); - } + for (size_t i = 0; i < nq; i++) + { + q[i] = psi_new_string_builder(); + char lbl[16]; + snprintf(lbl, sizeof lbl, "q%zu: ", i); + append_repeat(&q[i], " ", max_label - strlen(lbl)); + psi_string_builder_append(&q[i], lbl); + } + for (size_t i = 0; i < nc; i++) + { + c[i] = psi_new_string_builder(); + char lbl[16]; + snprintf(lbl, sizeof lbl, "c%zu: ", i); + append_repeat(&c[i], " ", max_label - strlen(lbl)); + psi_string_builder_append(&c[i], lbl); + } - struct PsiStringBuilder gap = psi_new_string_builder(); - append_repeat(&gap, " ", max_label); + struct PsiStringBuilder gap = psi_new_string_builder(); + append_repeat(&gap, " ", max_label); - if (circuit->operation_count == 0) - { - for (size_t i = 0; i < nq; i++) - psi_string_builder_append(&q[i], "───"); - for (size_t i = 0; i < nc; i++) - psi_string_builder_append(&c[i], "═══"); - psi_string_builder_append(&gap, " "); - } + if (circuit->operation_count == 0) + { + for (size_t i = 0; i < nq; i++) + psi_string_builder_append(&q[i], "───"); + for (size_t i = 0; i < nc; i++) + psi_string_builder_append(&c[i], "═══"); + psi_string_builder_append(&gap, " "); + } - for (size_t oi = 0; oi < circuit->operation_count; oi++) - { - struct PsiGateOp op = circuit->operations[oi]; + for (size_t oi = 0; oi < circuit->operation_count; oi++) + { + struct PsiGateOp op = circuit->operations[oi]; - size_t tc; - const size_t* targets = psi_gate_op_quantum_targets(&op, &tc); - size_t min_q = targets[0]; - size_t max_q = targets[0]; - for (size_t k = 1; k < tc; k++) - { - if (targets[k] < min_q) - min_q = targets[k]; - if (targets[k] > max_q) - max_q = targets[k]; - } + size_t tc; + const size_t* targets = psi_gate_op_quantum_targets(&op, &tc); + size_t min_q = targets[0]; + size_t max_q = targets[0]; + for (size_t k = 1; k < tc; k++) + { + if (targets[k] < min_q) + min_q = targets[k]; + if (targets[k] > max_q) + max_q = targets[k]; + } - if (is_single_target(op.kind)) - { - char label[64]; - single_label(op, label, sizeof label); - size_t w = psi_utf8_count(label); - size_t t = op.qubits[0]; + if (is_single_target(op.kind)) + { + char label[64]; + single_label(op, label, sizeof label); + size_t w = psi_utf8_count(label); + size_t t = op.qubits[0]; - for (size_t i = 0; i < nq; i++) - { - if (i == t) - { - psi_string_builder_append(&q[i], "─"); - psi_string_builder_append(&q[i], label); - psi_string_builder_append(&q[i], "─"); - } - else - append_repeat(&q[i], "─", w + 2); - } - for (size_t i = 0; i < nc; i++) - append_repeat(&c[i], "═", w + 2); - append_repeat(&gap, " ", w + 2); - } - else if (is_param_controlled(op.kind)) - { - char label[64]; - controlled_label(op, label, sizeof label); - size_t w = psi_utf8_count(label); - size_t control = op.qubits[0]; - size_t target = op.qubits[1]; + for (size_t i = 0; i < nq; i++) + { + if (i == t) + { + psi_string_builder_append(&q[i], "─"); + psi_string_builder_append(&q[i], label); + psi_string_builder_append(&q[i], "─"); + } + else + append_repeat(&q[i], "─", w + 2); + } + for (size_t i = 0; i < nc; i++) + append_repeat(&c[i], "═", w + 2); + append_repeat(&gap, " ", w + 2); + } + else if (is_param_controlled(op.kind)) + { + char label[64]; + controlled_label(op, label, sizeof label); + size_t w = psi_utf8_count(label); + size_t control = op.qubits[0]; + size_t target = op.qubits[1]; - for (size_t i = 0; i < nq; i++) - { - psi_string_builder_append(&q[i], "─"); - if (i == control) - { - psi_string_builder_append(&q[i], "●"); - append_repeat(&q[i], "─", w - 1); - } - else if (i == target) - psi_string_builder_append(&q[i], label); - else if (i > min_q && i < max_q) - { - psi_string_builder_append(&q[i], "│"); - append_repeat(&q[i], "─", w - 1); - } - else - append_repeat(&q[i], "─", w); - psi_string_builder_append(&q[i], "─"); - } - for (size_t i = 0; i < nc; i++) - append_repeat(&c[i], "═", w + 2); - append_repeat(&gap, " ", w + 2); - } - else if (op.kind == PSI_GATE_CNOT || op.kind == PSI_GATE_CZ || op.kind == PSI_GATE_SWAP || - op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP) - { - for (size_t i = 0; i < nq; i++) - { - const char* seg = "─────"; + for (size_t i = 0; i < nq; i++) + { + psi_string_builder_append(&q[i], "─"); + if (i == control) + { + psi_string_builder_append(&q[i], "●"); + append_repeat(&q[i], "─", w - 1); + } + else if (i == target) + psi_string_builder_append(&q[i], label); + else if (i > min_q && i < max_q) + { + psi_string_builder_append(&q[i], "│"); + append_repeat(&q[i], "─", w - 1); + } + else + append_repeat(&q[i], "─", w); + psi_string_builder_append(&q[i], "─"); + } + for (size_t i = 0; i < nc; i++) + append_repeat(&c[i], "═", w + 2); + append_repeat(&gap, " ", w + 2); + } + else if (op.kind == PSI_GATE_CNOT || op.kind == PSI_GATE_CZ || op.kind == PSI_GATE_SWAP || + op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP) + { + for (size_t i = 0; i < nq; i++) + { + const char* seg = "─────"; - switch (op.kind) - { - case PSI_GATE_CNOT: - if (i == op.qubits[0]) - seg = "──●──"; - else if (i == op.qubits[1]) - seg = "──⊕──"; - else if (i > min_q && i < max_q) - seg = "──│──"; - break; - case PSI_GATE_CZ: - if (i == op.qubits[0] || i == op.qubits[1]) - seg = "──●──"; - else if (i > min_q && i < max_q) - seg = "──│──"; - break; - case PSI_GATE_SWAP: - if (i == op.qubits[0] || i == op.qubits[1]) - seg = "──╳──"; - else if (i > min_q && i < max_q) - seg = "──│──"; - break; - case PSI_GATE_CCNOT: - if (i == op.qubits[0] || i == op.qubits[1]) - seg = "──●──"; - else if (i == op.qubits[2]) - seg = "──⊕──"; - else if (i > min_q && i < max_q) - seg = "──│──"; - break; - case PSI_GATE_CSWAP: - if (i == op.qubits[0]) - seg = "──●──"; - else if (i == op.qubits[1] || i == op.qubits[2]) - seg = "──╳──"; - else if (i > min_q && i < max_q) - seg = "──│──"; - break; - default: break; - } + switch (op.kind) + { + case PSI_GATE_CNOT: + if (i == op.qubits[0]) + seg = "──●──"; + else if (i == op.qubits[1]) + seg = "──⊕──"; + else if (i > min_q && i < max_q) + seg = "──│──"; + break; + case PSI_GATE_CZ: + if (i == op.qubits[0] || i == op.qubits[1]) + seg = "──●──"; + else if (i > min_q && i < max_q) + seg = "──│──"; + break; + case PSI_GATE_SWAP: + if (i == op.qubits[0] || i == op.qubits[1]) + seg = "──╳──"; + else if (i > min_q && i < max_q) + seg = "──│──"; + break; + case PSI_GATE_CCNOT: + if (i == op.qubits[0] || i == op.qubits[1]) + seg = "──●──"; + else if (i == op.qubits[2]) + seg = "──⊕──"; + else if (i > min_q && i < max_q) + seg = "──│──"; + break; + case PSI_GATE_CSWAP: + if (i == op.qubits[0]) + seg = "──●──"; + else if (i == op.qubits[1] || i == op.qubits[2]) + seg = "──╳──"; + else if (i > min_q && i < max_q) + seg = "──│──"; + break; + default: break; + } - psi_string_builder_append(&q[i], seg); - } - for (size_t i = 0; i < nc; i++) - psi_string_builder_append(&c[i], "═════"); - psi_string_builder_append(&gap, " "); - } - else if (op.kind == PSI_GATE_MEASURE) - { - size_t mq = op.qubits[0]; - size_t mc = op.classical; + psi_string_builder_append(&q[i], seg); + } + for (size_t i = 0; i < nc; i++) + psi_string_builder_append(&c[i], "═════"); + psi_string_builder_append(&gap, " "); + } + else if (op.kind == PSI_GATE_MEASURE) + { + size_t mq = op.qubits[0]; + size_t mc = op.classical; - for (size_t i = 0; i < nq; i++) - { - if (i == mq) - psi_string_builder_append(&q[i], "─[M]─"); - else if (i > mq) - psi_string_builder_append(&q[i], "──║──"); - else - psi_string_builder_append(&q[i], "─────"); - } - for (size_t i = 0; i < nc; i++) - { - if (i == mc) - psi_string_builder_append(&c[i], "══╩══"); - else if (i < mc) - psi_string_builder_append(&c[i], "══║══"); - else - psi_string_builder_append(&c[i], "═════"); - } - psi_string_builder_append(&gap, " ║ "); - } - else - { - char label[64]; - snprintf(label, sizeof label, "[%s]", op.custom->name); - size_t w = psi_utf8_count(label); + for (size_t i = 0; i < nq; i++) + { + if (i == mq) + psi_string_builder_append(&q[i], "─[M]─"); + else if (i > mq) + psi_string_builder_append(&q[i], "──║──"); + else + psi_string_builder_append(&q[i], "─────"); + } + for (size_t i = 0; i < nc; i++) + { + if (i == mc) + psi_string_builder_append(&c[i], "══╩══"); + else if (i < mc) + psi_string_builder_append(&c[i], "══║══"); + else + psi_string_builder_append(&c[i], "═════"); + } + psi_string_builder_append(&gap, " ║ "); + } + else + { + char label[64]; + snprintf(label, sizeof label, "[%s]", op.custom->name); + size_t w = psi_utf8_count(label); - for (size_t i = 0; i < nq; i++) - { - bool is_target = false; - for (size_t k = 0; k < tc; k++) - if (targets[k] == i) - is_target = true; + for (size_t i = 0; i < nq; i++) + { + bool is_target = false; + for (size_t k = 0; k < tc; k++) + if (targets[k] == i) + is_target = true; - psi_string_builder_append(&q[i], "─"); - if (is_target && i == targets[0]) - psi_string_builder_append(&q[i], label); - else if (is_target) - append_repeat(&q[i], "─", w); - else if (i > min_q && i < max_q) - { - psi_string_builder_append(&q[i], "│"); - append_repeat(&q[i], "─", w - 1); - } - else - append_repeat(&q[i], "─", w); - psi_string_builder_append(&q[i], "─"); - } - for (size_t i = 0; i < nc; i++) - append_repeat(&c[i], "═", w + 2); - append_repeat(&gap, " ", w + 2); - } - } + psi_string_builder_append(&q[i], "─"); + if (is_target && i == targets[0]) + psi_string_builder_append(&q[i], label); + else if (is_target) + append_repeat(&q[i], "─", w); + else if (i > min_q && i < max_q) + { + psi_string_builder_append(&q[i], "│"); + append_repeat(&q[i], "─", w - 1); + } + else + append_repeat(&q[i], "─", w); + psi_string_builder_append(&q[i], "─"); + } + for (size_t i = 0; i < nc; i++) + append_repeat(&c[i], "═", w + 2); + append_repeat(&gap, " ", w + 2); + } + } - struct PsiStringBuilder out = psi_new_string_builder(); + struct PsiStringBuilder out = psi_new_string_builder(); - for (size_t i = 0; i < nq; i++) - { - psi_string_builder_append(&out, psi_string_builder_finish(&q[i])); - psi_string_builder_append(&out, "░\n"); - free(q[i].data); - } + for (size_t i = 0; i < nq; i++) + { + psi_string_builder_append(&out, psi_string_builder_finish(&q[i])); + psi_string_builder_append(&out, "░\n"); + free(q[i].data); + } - if (nc > 0) - { - psi_string_builder_append(&out, psi_string_builder_finish(&gap)); - psi_string_builder_append(&out, "░\n"); - for (size_t i = 0; i < nc; i++) - { - psi_string_builder_append(&out, psi_string_builder_finish(&c[i])); - psi_string_builder_append(&out, "░\n"); - free(c[i].data); - } - } + if (nc > 0) + { + psi_string_builder_append(&out, psi_string_builder_finish(&gap)); + psi_string_builder_append(&out, "░\n"); + for (size_t i = 0; i < nc; i++) + { + psi_string_builder_append(&out, psi_string_builder_finish(&c[i])); + psi_string_builder_append(&out, "░\n"); + free(c[i].data); + } + } - free(gap.data); - free(q); - free(c); + free(gap.data); + free(q); + free(c); - return psi_string_builder_finish(&out); + return psi_string_builder_finish(&out); } diff --git a/src/visualizer/vertical_cli.c b/src/visualizer/vertical_cli.c index 4f21e49..340a2a5 100644 --- a/src/visualizer/vertical_cli.c +++ b/src/visualizer/vertical_cli.c @@ -7,317 +7,317 @@ static void gate_label(struct PsiGateOp op, char* out, size_t cap) { - switch (op.kind) - { - case PSI_GATE_H: snprintf(out, cap, "[H]"); break; - case PSI_GATE_X: snprintf(out, cap, "[X]"); break; - case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break; - case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break; - case PSI_GATE_S: snprintf(out, cap, "[S]"); break; - case PSI_GATE_T: snprintf(out, cap, "[T]"); break; - case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break; - case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break; - case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break; - case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break; - case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break; - case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break; - case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break; - case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break; - case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break; - case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break; - case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break; - case PSI_GATE_CRX: snprintf(out, cap, "[CRx]"); break; - case PSI_GATE_CRY: snprintf(out, cap, "[CRy]"); break; - case PSI_GATE_CRZ: snprintf(out, cap, "[CRz]"); break; - case PSI_GATE_CP: snprintf(out, cap, "[CP]"); break; - case PSI_GATE_CNOT: snprintf(out, cap, "●"); break; - case PSI_GATE_CZ: snprintf(out, cap, "●"); break; - case PSI_GATE_SWAP: snprintf(out, cap, "╳"); break; - case PSI_GATE_CCNOT: snprintf(out, cap, "●"); break; - case PSI_GATE_CSWAP: snprintf(out, cap, "●"); break; - case PSI_GATE_MEASURE: snprintf(out, cap, "[M]"); break; - case PSI_GATE_CUSTOM: snprintf(out, cap, "[%s]", op.custom->name); break; - } + switch (op.kind) + { + case PSI_GATE_H: snprintf(out, cap, "[H]"); break; + case PSI_GATE_X: snprintf(out, cap, "[X]"); break; + case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break; + case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break; + case PSI_GATE_S: snprintf(out, cap, "[S]"); break; + case PSI_GATE_T: snprintf(out, cap, "[T]"); break; + case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break; + case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break; + case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break; + case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break; + case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break; + case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break; + case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break; + case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break; + case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break; + case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break; + case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break; + case PSI_GATE_CRX: snprintf(out, cap, "[CRx]"); break; + case PSI_GATE_CRY: snprintf(out, cap, "[CRy]"); break; + case PSI_GATE_CRZ: snprintf(out, cap, "[CRz]"); break; + case PSI_GATE_CP: snprintf(out, cap, "[CP]"); break; + case PSI_GATE_CNOT: snprintf(out, cap, "●"); break; + case PSI_GATE_CZ: snprintf(out, cap, "●"); break; + case PSI_GATE_SWAP: snprintf(out, cap, "╳"); break; + case PSI_GATE_CCNOT: snprintf(out, cap, "●"); break; + case PSI_GATE_CSWAP: snprintf(out, cap, "●"); break; + case PSI_GATE_MEASURE: snprintf(out, cap, "[M]"); break; + case PSI_GATE_CUSTOM: snprintf(out, cap, "[%s]", op.custom->name); break; + } } static size_t calculate_col_width(const struct PsiQuantumCircuit* circuit) { - size_t max_label = 3; + size_t max_label = 3; - for (size_t i = 0; i < circuit->operation_count; i++) - { - char label[64]; - gate_label(circuit->operations[i], label, sizeof label); - size_t n = psi_utf8_count(label); - if (n > max_label) - max_label = n; - } + for (size_t i = 0; i < circuit->operation_count; i++) + { + char label[64]; + gate_label(circuit->operations[i], label, sizeof label); + size_t n = psi_utf8_count(label); + if (n > max_label) + max_label = n; + } - size_t width = max_label + 2; - if (width % 2 == 0) - return width + 1; + size_t width = max_label + 2; + if (width % 2 == 0) + return width + 1; - return width; + return width; } static bool is_single_target(enum PsiGateKind kind) { - switch (kind) - { - case PSI_GATE_H: - case PSI_GATE_X: - case PSI_GATE_Y: - case PSI_GATE_Z: - case PSI_GATE_S: - case PSI_GATE_T: - case PSI_GATE_SDG: - case PSI_GATE_TDG: - case PSI_GATE_SX: - case PSI_GATE_SXDG: - case PSI_GATE_RX: - case PSI_GATE_RY: - case PSI_GATE_RZ: - case PSI_GATE_P: - case PSI_GATE_U1: - case PSI_GATE_U2: - case PSI_GATE_U3: return true; - default: return false; - } + switch (kind) + { + case PSI_GATE_H: + case PSI_GATE_X: + case PSI_GATE_Y: + case PSI_GATE_Z: + case PSI_GATE_S: + case PSI_GATE_T: + case PSI_GATE_SDG: + case PSI_GATE_TDG: + case PSI_GATE_SX: + case PSI_GATE_SXDG: + case PSI_GATE_RX: + case PSI_GATE_RY: + case PSI_GATE_RZ: + case PSI_GATE_P: + case PSI_GATE_U1: + case PSI_GATE_U2: + case PSI_GATE_U3: return true; + default: return false; + } } static bool is_param_controlled(enum PsiGateKind kind) { - switch (kind) - { - case PSI_GATE_CRX: - case PSI_GATE_CRY: - case PSI_GATE_CRZ: - case PSI_GATE_CP: return true; - default: return false; - } + switch (kind) + { + case PSI_GATE_CRX: + case PSI_GATE_CRY: + case PSI_GATE_CRZ: + case PSI_GATE_CP: return true; + default: return false; + } } char* psi_render_circuit_vertical(const struct PsiQuantumCircuit* circuit) { - struct PsiStringBuilder sb = psi_new_string_builder(); + struct PsiStringBuilder sb = psi_new_string_builder(); - size_t nq = circuit->num_qubits; - size_t nc = circuit->num_classical; + size_t nq = circuit->num_qubits; + size_t nc = circuit->num_classical; - if (nq == 0) - return psi_string_builder_finish(&sb); + if (nq == 0) + return psi_string_builder_finish(&sb); - size_t col_width = calculate_col_width(circuit); - size_t gap_width = 3; - size_t stride = col_width + 1; - size_t half = col_width / 2; + size_t col_width = calculate_col_width(circuit); + size_t gap_width = 3; + size_t stride = col_width + 1; + size_t half = col_width / 2; - size_t q_total = nq * col_width + (nq - 1); - size_t c_total = nc > 0 ? nc * col_width + (nc - 1) : 0; - size_t total_width = q_total + gap_width + c_total; + size_t q_total = nq * col_width + (nq - 1); + size_t c_total = nc > 0 ? nc * col_width + (nc - 1) : 0; + size_t total_width = q_total + gap_width + c_total; - struct PsiGlyphRow header = psi_new_glyph_row(total_width); - for (size_t i = 0; i < nq; i++) - { - char label[16]; - snprintf(label, sizeof label, "q%zu", i); - size_t col_start = i * stride; - psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label); - } - for (size_t i = 0; i < nc; i++) - { - char label[16]; - snprintf(label, sizeof label, "c%zu", i); - size_t col_start = q_total + gap_width + i * stride; - psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label); - } - psi_glyph_row_render(header, &sb); - psi_free_glyph_row(&header); + struct PsiGlyphRow header = psi_new_glyph_row(total_width); + for (size_t i = 0; i < nq; i++) + { + char label[16]; + snprintf(label, sizeof label, "q%zu", i); + size_t col_start = i * stride; + psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label); + } + for (size_t i = 0; i < nc; i++) + { + char label[16]; + snprintf(label, sizeof label, "c%zu", i); + size_t col_start = q_total + gap_width + i * stride; + psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label); + } + psi_glyph_row_render(header, &sb); + psi_free_glyph_row(&header); - for (size_t op_index = 0; op_index <= circuit->operation_count; op_index++) - { - struct PsiGlyphRow wires = psi_new_glyph_row(total_width); - for (size_t i = 0; i < nq; i++) - psi_glyph_row_set(&wires, i * stride + half, "│"); - for (size_t i = 0; i < nc; i++) - psi_glyph_row_set(&wires, q_total + gap_width + i * stride + half, "║"); - psi_glyph_row_render(wires, &sb); - psi_free_glyph_row(&wires); + for (size_t op_index = 0; op_index <= circuit->operation_count; op_index++) + { + struct PsiGlyphRow wires = psi_new_glyph_row(total_width); + for (size_t i = 0; i < nq; i++) + psi_glyph_row_set(&wires, i * stride + half, "│"); + for (size_t i = 0; i < nc; i++) + psi_glyph_row_set(&wires, q_total + gap_width + i * stride + half, "║"); + psi_glyph_row_render(wires, &sb); + psi_free_glyph_row(&wires); - if (op_index == circuit->operation_count) - break; + if (op_index == circuit->operation_count) + break; - struct PsiGateOp op = circuit->operations[op_index]; + struct PsiGateOp op = circuit->operations[op_index]; - size_t target_count; - const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count); - size_t min_q = targets[0]; - size_t max_q = targets[0]; - for (size_t i = 1; i < target_count; i++) - { - if (targets[i] < min_q) - min_q = targets[i]; - if (targets[i] > max_q) - max_q = targets[i]; - } + size_t target_count; + const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count); + size_t min_q = targets[0]; + size_t max_q = targets[0]; + for (size_t i = 1; i < target_count; i++) + { + if (targets[i] < min_q) + min_q = targets[i]; + if (targets[i] > max_q) + max_q = targets[i]; + } - char label[64]; - gate_label(op, label, sizeof label); - size_t label_len = psi_utf8_count(label); + char label[64]; + gate_label(op, label, sizeof label); + size_t label_len = psi_utf8_count(label); - struct PsiGlyphRow row = psi_new_glyph_row(total_width); + struct PsiGlyphRow row = psi_new_glyph_row(total_width); - if (is_single_target(op.kind)) - { - size_t target = op.qubits[0]; - for (size_t i = 0; i < nq; i++) - { - size_t col_start = i * stride; - if (i == target) - psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); - else - psi_glyph_row_set(&row, col_start + half, "│"); - } - for (size_t i = 0; i < nc; i++) - psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); - } - else if (op.kind == PSI_GATE_MEASURE) - { - size_t mq = op.qubits[0]; - size_t mc = op.classical; - for (size_t i = 0; i < nq; i++) - { - size_t col_start = i * stride; - if (i < mq) - psi_glyph_row_set(&row, col_start + half, "│"); - else if (i == mq) - psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); - } + if (is_single_target(op.kind)) + { + size_t target = op.qubits[0]; + for (size_t i = 0; i < nq; i++) + { + size_t col_start = i * stride; + if (i == target) + psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); + else + psi_glyph_row_set(&row, col_start + half, "│"); + } + for (size_t i = 0; i < nc; i++) + psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); + } + else if (op.kind == PSI_GATE_MEASURE) + { + size_t mq = op.qubits[0]; + size_t mc = op.classical; + for (size_t i = 0; i < nq; i++) + { + size_t col_start = i * stride; + if (i < mq) + psi_glyph_row_set(&row, col_start + half, "│"); + else if (i == mq) + psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); + } - size_t mq_center = mq * stride + half; - size_t mc_start = q_total + gap_width; - size_t mc_center = mc_start + mc * stride + half; + size_t mq_center = mq * stride + half; + size_t mc_start = q_total + gap_width; + size_t mc_center = mc_start + mc * stride + half; - psi_glyph_row_fill_space(&row, mq_center + 2, mc_center + 1, "═"); - psi_glyph_row_set(&row, mc_center, "╣"); + psi_glyph_row_fill_space(&row, mq_center + 2, mc_center + 1, "═"); + psi_glyph_row_set(&row, mc_center, "╣"); - for (size_t i = 0; i < nc; i++) - if (i > mc) - psi_glyph_row_set(&row, mc_start + i * stride + half, "║"); - } - else if (op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP) - { - bool is_cswap = op.kind == PSI_GATE_CSWAP; - const char* sym_c = "●"; - const char* sym_t = is_cswap ? "╳" : "⊕"; - size_t c1 = op.qubits[0]; - size_t c2 = op.qubits[1]; - size_t t = op.qubits[2]; + for (size_t i = 0; i < nc; i++) + if (i > mc) + psi_glyph_row_set(&row, mc_start + i * stride + half, "║"); + } + else if (op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP) + { + bool is_cswap = op.kind == PSI_GATE_CSWAP; + const char* sym_c = "●"; + const char* sym_t = is_cswap ? "╳" : "⊕"; + size_t c1 = op.qubits[0]; + size_t c2 = op.qubits[1]; + size_t t = op.qubits[2]; - for (size_t i = 0; i < nq; i++) - { - size_t center = i * stride + half; - if (i < min_q || i > max_q) - psi_glyph_row_set(&row, center, "│"); - else if (i == c1) - psi_glyph_row_set(&row, center, sym_c); - else if (i == c2) - psi_glyph_row_set(&row, center, is_cswap ? sym_t : sym_c); - else if (i == t) - psi_glyph_row_set(&row, center, sym_t); - } + for (size_t i = 0; i < nq; i++) + { + size_t center = i * stride + half; + if (i < min_q || i > max_q) + psi_glyph_row_set(&row, center, "│"); + else if (i == c1) + psi_glyph_row_set(&row, center, sym_c); + else if (i == c2) + psi_glyph_row_set(&row, center, is_cswap ? sym_t : sym_c); + else if (i == t) + psi_glyph_row_set(&row, center, sym_t); + } - psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─"); - for (size_t i = 0; i < nc; i++) - psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); - } - else if (op.kind == PSI_GATE_CUSTOM) - { - if (target_count == 1) - { - for (size_t i = 0; i < nq; i++) - { - size_t col_start = i * stride; - if (i == targets[0]) - psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); - else - psi_glyph_row_set(&row, col_start + half, "│"); - } - } - else - { - for (size_t i = 0; i < nq; i++) - { - size_t col_start = i * stride; - size_t center = col_start + half; - bool is_target = false; - for (size_t k = 0; k < target_count; k++) - if (targets[k] == i) - is_target = true; + psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─"); + for (size_t i = 0; i < nc; i++) + psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); + } + else if (op.kind == PSI_GATE_CUSTOM) + { + if (target_count == 1) + { + for (size_t i = 0; i < nq; i++) + { + size_t col_start = i * stride; + if (i == targets[0]) + psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); + else + psi_glyph_row_set(&row, col_start + half, "│"); + } + } + else + { + for (size_t i = 0; i < nq; i++) + { + size_t col_start = i * stride; + size_t center = col_start + half; + bool is_target = false; + for (size_t k = 0; k < target_count; k++) + if (targets[k] == i) + is_target = true; - if (i < min_q || i > max_q) - psi_glyph_row_set(&row, center, "│"); - else if (i == targets[0]) - psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); - else if (is_target) - psi_glyph_row_set(&row, center, "□"); - } + if (i < min_q || i > max_q) + psi_glyph_row_set(&row, center, "│"); + else if (i == targets[0]) + psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); + else if (is_target) + psi_glyph_row_set(&row, center, "□"); + } - psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, - "─"); - } + psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, + "─"); + } - for (size_t i = 0; i < nc; i++) - psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); - } - else - { - const char* sym1 = "●"; - const char* sym2 = "⊕"; - if (op.kind == PSI_GATE_CZ) - sym2 = "●"; - else if (op.kind == PSI_GATE_SWAP) - { - sym1 = "╳"; - sym2 = "╳"; - } - else if (is_param_controlled(op.kind)) - sym2 = "□"; + for (size_t i = 0; i < nc; i++) + psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); + } + else + { + const char* sym1 = "●"; + const char* sym2 = "⊕"; + if (op.kind == PSI_GATE_CZ) + sym2 = "●"; + else if (op.kind == PSI_GATE_SWAP) + { + sym1 = "╳"; + sym2 = "╳"; + } + else if (is_param_controlled(op.kind)) + sym2 = "□"; - size_t control = op.qubits[0]; - size_t target = op.qubits[1]; + size_t control = op.qubits[0]; + size_t target = op.qubits[1]; - for (size_t i = 0; i < nq; i++) - { - size_t col_start = i * stride; - size_t center = col_start + half; - if (i < min_q || i > max_q) - psi_glyph_row_set(&row, center, "│"); - else if (i == control) - psi_glyph_row_set(&row, center, sym1); - else if (i == target) - { - if (is_param_controlled(op.kind)) - psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); - else - psi_glyph_row_set(&row, center, sym2); - } - } + for (size_t i = 0; i < nq; i++) + { + size_t col_start = i * stride; + size_t center = col_start + half; + if (i < min_q || i > max_q) + psi_glyph_row_set(&row, center, "│"); + else if (i == control) + psi_glyph_row_set(&row, center, sym1); + else if (i == target) + { + if (is_param_controlled(op.kind)) + psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label); + else + psi_glyph_row_set(&row, center, sym2); + } + } - psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─"); - for (size_t i = 0; i < nc; i++) - psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); - } + psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─"); + for (size_t i = 0; i < nc; i++) + psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║"); + } - psi_glyph_row_render(row, &sb); - psi_free_glyph_row(&row); - } + psi_glyph_row_render(row, &sb); + psi_free_glyph_row(&row); + } - struct PsiGlyphRow end_row = psi_new_glyph_row(total_width); - for (size_t i = 0; i < total_width; i++) - psi_glyph_row_set(&end_row, i, "░"); - psi_glyph_row_render(end_row, &sb); - psi_free_glyph_row(&end_row); + struct PsiGlyphRow end_row = psi_new_glyph_row(total_width); + for (size_t i = 0; i < total_width; i++) + psi_glyph_row_set(&end_row, i, "░"); + psi_glyph_row_render(end_row, &sb); + psi_free_glyph_row(&end_row); - return psi_string_builder_finish(&sb); + return psi_string_builder_finish(&sb); } |
