From: Graph <graphgalaxyapp@gmail.com> Date: Wed, 3 Feb 2021 16:17:35 +0000 (+0800) Subject: Keep the edge order in json output X-Git-Tag: 2.47.0~89^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee2b7b100431d910314d66e786a2508cf5ba7c12;p=graphviz Keep the edge order in json output --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dfb7920b..d8fe2a61f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- The edges in JSON output are ordered now !1728 + ### Fixed - typos in gpcanvas.c #1927 diff --git a/plugin/core/gvrender_core_json.c b/plugin/core/gvrender_core_json.c index 8c22dddfd..e53c4c239 100644 --- a/plugin/core/gvrender_core_json.c +++ b/plugin/core/gvrender_core_json.c @@ -33,6 +33,8 @@ #include <gvc/gvio.h> #include <gvc/gvcint.h> +#include <common/memory.h> + typedef enum { FORMAT_JSON, FORMAT_JSON0, @@ -460,6 +462,22 @@ static int write_subgs(Agraph_t * g, GVJ_t * job, int top, state_t* sp) return 1; } +static int agseqasc(Agedge_t **lhs, Agedge_t **rhs) +{ + Agedge_t *e1 = *lhs; + Agedge_t *e2 = *rhs; + + if (AGSEQ(e1) < AGSEQ(e2)) { + return -1; + } + else if (AGSEQ(e1) > AGSEQ(e2)) { + return 1; + } + else { + return 0; + } +} + static void write_edge(Agedge_t * e, GVJ_t * job, int top, state_t* sp) { if (top) { @@ -484,39 +502,49 @@ static void write_edge(Agedge_t * e, GVJ_t * job, int top, state_t* sp) static int write_edges(Agraph_t * g, GVJ_t * job, int top, state_t* sp) { - Agnode_t* np; - Agedge_t* ep; + size_t count = 0; int not_first = 0; - np = agfstnode(g); - if (!np) return 0; - ep = NULL; - /* find a first edge */ - for (; np; np = agnxtnode(g,np)) { - for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) { - if (ep) break; - } - if (ep) break; + for (Agnode_t *np = agfstnode(g); np; np = agnxtnode(g, np)) { + for (Agedge_t *ep = agfstout(g, np); ep; ep = agnxtout(g, ep)) { + ++count; + } } - if (!ep) return 0; + + if (count == 0) { + return 0; + } + + Agedge_t **edges = gcalloc(count, sizeof(Agedge_t *)); + + size_t i = 0; + for (Agnode_t *np = agfstnode(g); np; np = agnxtnode(g, np)) { + for (Agedge_t *ep = agfstout(g, np); ep; ep = agnxtout(g, ep)) { + edges[i] = ep; + ++i; + } + } + + qsort(edges, count, sizeof(Agedge_t *), (qsort_cmpf)agseqasc); gvputs(job, ",\n"); indent(job, sp->Level++); gvputs(job, "\"edges\": [\n"); if (!top) indent(job, sp->Level); - for (; np; np = agnxtnode(g,np)) { - for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) { - if (not_first) - if (top) - gvputs(job, ",\n"); - else - gvputs(job, ","); - else - not_first = 1; - write_edge(ep, job, top, sp); - } + for (size_t j = 0; j < count; ++j) { + if (not_first) + if (top) + gvputs(job, ",\n"); + else + gvputs(job, ","); + else + not_first = 1; + write_edge(edges[j], job, top, sp); } + + free(edges); + sp->Level--; gvputs(job, "\n"); indent(job, sp->Level); diff --git a/rtest/test_misc.py b/rtest/test_misc.py index d0e52704d..8ce48fddd 100644 --- a/rtest/test_misc.py +++ b/rtest/test_misc.py @@ -1,5 +1,4 @@ import json -import pytest import subprocess def test_json_node_order(): @@ -35,7 +34,6 @@ def test_json_node_order(): # the nodes should appear in the order in which they were seen in the input assert nodes == ['1', '2', '4', '5', '7', '6', '3', '8'] -@pytest.mark.xfail(strict=True) def test_json_edge_order(): ''' test that edges appear in JSON output in the same order as they were input