xpath OPTIMIZE avoid redundant vars/mallocs in canonization
diff --git a/src/xpath.c b/src/xpath.c
index acb7a9c..25982e2 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -53,6 +53,7 @@
         enum lyxp_axis axis, uint32_t options);
 static LY_ERR moveto_scnode(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname,
         enum lyxp_axis axis, uint32_t options);
+static LY_ERR moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op);
 
 /* Functions are divided into the following basic classes:
  *
@@ -1604,14 +1605,15 @@
 /**
  * @brief Set cast for comparisons.
  *
- * @param[in] trg Target set to cast source into.
+ * @param[in,out] trg Target set to cast source into.
  * @param[in] src Source set.
  * @param[in] type Target set type.
  * @param[in] src_idx Source set node index.
- * @return LY_ERR
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR value on error.
  */
 static LY_ERR
-set_comp_cast(struct lyxp_set *trg, struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
+set_comp_cast(struct lyxp_set *trg, const struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
 {
     assert(src->type == LYXP_SET_NODE_SET);
 
@@ -1627,22 +1629,21 @@
 /**
  * @brief Set content canonization for comparisons.
  *
- * @param[in] trg Target set to put the canononized source into.
- * @param[in] src Source set.
+ * @param[in,out] set Set to canonize.
  * @param[in] xp_node Source XPath node/meta to use for canonization.
- * @return LY_ERR
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR value on error.
  */
 static LY_ERR
-set_comp_canonize(struct lyxp_set *trg, const struct lyxp_set *src, const struct lyxp_set_node *xp_node)
+set_comp_canonize(struct lyxp_set *set, const struct lyxp_set_node *xp_node)
 {
     const struct lysc_type *type = NULL;
     struct lyd_value val;
     struct ly_err_item *err = NULL;
-    char *str, *ptr;
     LY_ERR rc;
 
     /* is there anything to canonize even? */
-    if ((src->type == LYXP_SET_NUMBER) || (src->type == LYXP_SET_STRING)) {
+    if (set->type == LYXP_SET_STRING) {
         /* do we have a type to use for canonization? */
         if ((xp_node->type == LYXP_NODE_ELEM) && (xp_node->node->schema->nodetype & LYD_NODE_TERM)) {
             type = ((struct lyd_node_term *)xp_node->node)->value.realtype;
@@ -1651,45 +1652,39 @@
         }
     }
     if (!type) {
-        goto fill;
+        /* no canonization needed/possible */
+        return LY_SUCCESS;
     }
 
-    if (src->type == LYXP_SET_NUMBER) {
-        /* canonize number */
-        if (asprintf(&str, "%Lf", src->val.num) == -1) {
-            LOGMEM(src->ctx);
-            return LY_EMEM;
-        }
-    } else {
-        /* canonize string */
-        str = strdup(src->val.str);
+    /* check for built-in types without required canonization */
+    if ((type->basetype == LY_TYPE_STRING) && (type->plugin->store == lyplg_type_store_string)) {
+        /* string */
+        return LY_SUCCESS;
+    }
+    if ((type->basetype == LY_TYPE_BOOL) && (type->plugin->store == lyplg_type_store_boolean)) {
+        /* boolean */
+        return LY_SUCCESS;
+    }
+    if ((type->basetype == LY_TYPE_ENUM) && (type->plugin->store == lyplg_type_store_enum)) {
+        /* enumeration */
+        return LY_SUCCESS;
     }
 
-    /* ignore errors, the value may not satisfy schema constraints */
-    rc = type->plugin->store(src->ctx, type, str, strlen(str), LYPLG_TYPE_STORE_DYNAMIC, src->format, src->prefix_data,
+    /* print canonized string, ignore errors, the value may not satisfy schema constraints */
+    rc = type->plugin->store(set->ctx, type, set->val.str, strlen(set->val.str), 0, set->format, set->prefix_data,
             LYD_HINT_DATA, xp_node->node->schema, &val, NULL, &err);
     ly_err_free(err);
     if (rc) {
-        /* invalid value */
-        /* function store automaticaly dealloc value when fail */
-        goto fill;
+        /* invalid value, function store automaticaly dealloc value when fail */
+        return LY_SUCCESS;
     }
 
-    /* use the canonized value */
-    set_init(trg, src);
-    trg->type = src->type;
-    if (src->type == LYXP_SET_NUMBER) {
-        trg->val.num = strtold(type->plugin->print(src->ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL), &ptr);
-        LY_CHECK_ERR_RET(ptr[0], LOGINT(src->ctx), LY_EINT);
-    } else {
-        trg->val.str = strdup(type->plugin->print(src->ctx, &val, LY_VALUE_CANON, NULL, NULL, NULL));
-    }
-    type->plugin->free(src->ctx, &val);
-    return LY_SUCCESS;
+    /* use the canonized string value */
+    free(set->val.str);
+    set->val.str = strdup(lyd_value_get_canonical(set->ctx, &val));
+    type->plugin->free(set->ctx, &val);
+    LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
 
-fill:
-    /* no canonization needed/possible */
-    set_fill_set(trg, src);
     return LY_SUCCESS;
 }
 
@@ -7095,17 +7090,67 @@
 }
 
 /**
- * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
+ * @brief Move context @p set1 single item to the result of a comparison.
+ *
+ * @param[in] set1 First set with the item to compare.
+ * @param[in] idx1 Index of the item in @p set1.
+ * @param[in] set2 Second set.
+ * @param[in] op Comparison operator to process.
+ * @param[in] switch_operands Whether to switch sets as operands; whether it is `set1 op set2` or `set2 op set1`.
+ * @param[out] result Result of the comparison.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+moveto_op_comp_item(const struct lyxp_set *set1, uint32_t idx1, struct lyxp_set *set2, const char *op,
+        ly_bool switch_operands, ly_bool *result)
+{
+    struct lyxp_set tmp1 = {0};
+    LY_ERR rc = LY_SUCCESS;
+
+    assert(set1->type == LYXP_SET_NODE_SET);
+
+    /* cast set1 */
+    switch (set2->type) {
+    case LYXP_SET_NUMBER:
+        rc = set_comp_cast(&tmp1, set1, LYXP_SET_NUMBER, idx1);
+        break;
+    case LYXP_SET_BOOLEAN:
+        rc = set_comp_cast(&tmp1, set1, LYXP_SET_BOOLEAN, idx1);
+        break;
+    default:
+        rc = set_comp_cast(&tmp1, set1, LYXP_SET_STRING, idx1);
+        break;
+    }
+    LY_CHECK_GOTO(rc, cleanup);
+
+    /* canonize set2 */
+    LY_CHECK_GOTO(rc = set_comp_canonize(set2, &set1->val.nodes[idx1]), cleanup);
+
+    /* compare recursively and store the result */
+    if (switch_operands) {
+        LY_CHECK_GOTO(rc = moveto_op_comp(set2, &tmp1, op), cleanup);
+        *result = set2->val.bln;
+    } else {
+        LY_CHECK_GOTO(rc = moveto_op_comp(&tmp1, set2, op), cleanup);
+        *result = tmp1.val.bln;
+    }
+
+cleanup:
+    lyxp_set_free_content(&tmp1);
+    return rc;
+}
+
+/**
+ * @brief Move context @p set1 to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
  *        Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
  *
  * @param[in,out] set1 Set to use for the result.
  * @param[in] set2 Set acting as the second operand for @p op.
  * @param[in] op Comparison operator to process.
- * @param[in] options XPath options.
  * @return LY_ERR
  */
 static LY_ERR
-moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, uint32_t options)
+moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
 {
     /*
      * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
@@ -7138,79 +7183,37 @@
      * NUMBER + BOOLEAN = NUMBER + NUMBER      /(1 NUMBER) 2 NUMBER
      * STRING + BOOLEAN = NUMBER + NUMBER      /(1 NUMBER) 2 NUMBER
      */
-    struct lyxp_set iter1, iter2;
-    int result;
-    int64_t i;
+    ly_bool result;
+    uint32_t i;
     LY_ERR rc;
 
-    memset(&iter1, 0, sizeof iter1);
-    memset(&iter2, 0, sizeof iter2);
-
     /* iterative evaluation with node-sets */
     if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
         if (set1->type == LYXP_SET_NODE_SET) {
             for (i = 0; i < set1->used; ++i) {
-                /* cast set1 */
-                switch (set2->type) {
-                case LYXP_SET_NUMBER:
-                    rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
-                    break;
-                case LYXP_SET_BOOLEAN:
-                    rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
-                    break;
-                default:
-                    rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
-                    break;
-                }
-                LY_CHECK_RET(rc);
-
-                /* canonize set2 */
-                LY_CHECK_ERR_RET(rc = set_comp_canonize(&iter2, set2, &set1->val.nodes[i]), lyxp_set_free_content(&iter1), rc);
-
-                /* compare recursively */
-                rc = moveto_op_comp(&iter1, &iter2, op, options);
-                lyxp_set_free_content(&iter2);
-                LY_CHECK_ERR_RET(rc, lyxp_set_free_content(&iter1), rc);
+                /* evaluate for the single item */
+                LY_CHECK_RET(moveto_op_comp_item(set1, i, set2, op, 0, &result));
 
                 /* lazy evaluation until true */
-                if (iter1.val.bln) {
+                if (result) {
                     set_fill_boolean(set1, 1);
                     return LY_SUCCESS;
                 }
             }
         } else {
             for (i = 0; i < set2->used; ++i) {
-                /* set set2 */
-                switch (set1->type) {
-                case LYXP_SET_NUMBER:
-                    rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
-                    break;
-                case LYXP_SET_BOOLEAN:
-                    rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
-                    break;
-                default:
-                    rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
-                    break;
-                }
-                LY_CHECK_RET(rc);
-
-                /* canonize set1 */
-                LY_CHECK_ERR_RET(rc = set_comp_canonize(&iter1, set1, &set2->val.nodes[i]), lyxp_set_free_content(&iter2), rc);
-
-                /* compare recursively */
-                rc = moveto_op_comp(&iter1, &iter2, op, options);
-                lyxp_set_free_content(&iter2);
-                LY_CHECK_ERR_RET(rc, lyxp_set_free_content(&iter1), rc);
+                /* evaluate for the single item */
+                LY_CHECK_RET(moveto_op_comp_item(set2, i, set1, op, 1, &result));
 
                 /* lazy evaluation until true */
-                if (iter1.val.bln) {
+                if (result) {
                     set_fill_boolean(set1, 1);
                     return LY_SUCCESS;
                 }
             }
         }
 
-        /* false for all nodes */
+        /* false for all the nodes */
         set_fill_boolean(set1, 0);
         return LY_SUCCESS;
     }
@@ -8977,7 +8980,7 @@
             lyxp_set_scnode_merge(set, &set2);
             set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
         } else {
-            rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
+            rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
             LY_CHECK_GOTO(rc, cleanup);
         }
     }
@@ -9046,7 +9049,7 @@
             lyxp_set_scnode_merge(set, &set2);
             set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
         } else {
-            rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
+            rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
             LY_CHECK_GOTO(rc, cleanup);
         }
     }