From 5e3efed788f4b184ed02d147588ff53c20c244f5 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 11 Nov 2020 21:03:53 +0100 Subject: Fix flaky literal comparison --- NEWS | 3 ++- src/sord.c | 51 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 506fb04..c2a0a35 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,9 @@ sord (0.16.7) unstable; * Clean up code + * Fix potentially incorrect search results - -- David Robillard Wed, 11 Nov 2020 12:28:08 +0000 + -- David Robillard Wed, 11 Nov 2020 19:34:26 +0000 sord (0.16.6) stable; diff --git a/src/sord.c b/src/sord.c index 958a6db..5a759c0 100644 --- a/src/sord.c +++ b/src/sord.c @@ -232,6 +232,42 @@ sord_world_set_error_sink(SordWorld* world, world->error_handle = handle; } +static inline int +sord_node_compare_literal(const SordNode* a, const SordNode* b) +{ + const int cmp = strcmp((const char*)sord_node_get_string(a), + (const char*)sord_node_get_string(b)); + if (cmp != 0) { + return cmp; + } + + const bool a_has_lang = a->meta.lit.lang[0]; + const bool b_has_lang = b->meta.lit.lang[0]; + const bool a_has_datatype = a->meta.lit.datatype; + const bool b_has_datatype = b->meta.lit.datatype; + const bool a_has_meta = a_has_lang || a_has_datatype; + const bool b_has_meta = b_has_lang || b_has_datatype; + + assert(!(a_has_lang && a_has_datatype)); + assert(!(b_has_lang && b_has_datatype)); + + if (!a_has_meta && !b_has_meta) { + return 0; + } else if (!a_has_meta || (a_has_lang && b_has_datatype)) { + return -1; + } else if (!b_has_meta || (a_has_datatype && b_has_lang)) { + return 1; + } else if (a_has_lang) { + assert(b_has_lang); + return strcmp(a->meta.lit.lang, b->meta.lit.lang); + } + + assert(a_has_datatype); + assert(b_has_datatype); + return strcmp((const char*)a->meta.lit.datatype->node.buf, + (const char*)b->meta.lit.datatype->node.buf); +} + /** Compare nodes, considering NULL a wildcard match. */ static inline int sord_node_compare(const SordNode* a, const SordNode* b) @@ -248,20 +284,7 @@ sord_node_compare(const SordNode* a, const SordNode* b) case SERD_BLANK: return strcmp((const char*)a->node.buf, (const char*)b->node.buf); case SERD_LITERAL: - cmp = strcmp((const char*)sord_node_get_string(a), - (const char*)sord_node_get_string(b)); - if (cmp == 0) { - // Note: Can't use sord_node_compare here since it does wildcards - if (!a->meta.lit.datatype || !b->meta.lit.datatype) { - cmp = (a->meta.lit.datatype < b->meta.lit.datatype) ? -1 : 1; - } else { - cmp = strcmp((const char*)a->meta.lit.datatype->node.buf, - (const char*)b->meta.lit.datatype->node.buf); - } - } - if (cmp == 0) { - cmp = strcmp(a->meta.lit.lang, b->meta.lit.lang); - } + cmp = sord_node_compare_literal(a, b); break; default: break; -- cgit v1.2.1