Commit e45d6e2fad69d68535dca386bbbcd2fc26e0ea2f

Thomas de Grivel 2023-11-19T20:44:37

compare_map

diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 538fd5f..4a49795 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -1859,6 +1859,7 @@ sw buf_parse_map (s_buf *buf, s_map *dest)
   buf_save_init(buf, &save);
   if ((r = buf_read_1(buf, "%{")) <= 0)
     goto clean;
+  result += r;
   keys = NULL;
   keys_end = &keys;
   values = NULL;
diff --git a/libc3/compare.c b/libc3/compare.c
index b3ee036..1d15169 100644
--- a/libc3/compare.c
+++ b/libc3/compare.c
@@ -298,6 +298,27 @@ s8 compare_list (const s_list *a, const s_list *b)
   }
 }
 
+s8 compare_map (const s_map *a, const s_map *b)
+{
+  uw i = 0;
+  s8 r;
+  assert(a);
+  assert(b);
+  if (a == b)
+    return 0;
+  if (a->count < b->count)
+    return -1;
+  if (a->count > b->count)
+    return 1;
+  while (i < a->count) {
+    if ((r = compare_tag(a->keys + i, b->keys + i)) ||
+        (r = compare_tag(a->values + i, b->values + i)))
+      return r;
+    i++;
+  }
+  return 0;
+}
+
 s8 compare_ptag (const p_tag a, const p_tag b)
 {
   if (a < b)
@@ -777,6 +798,7 @@ s8 compare_tag (const s_tag *a, const s_tag *b) {
   case TAG_FN: return compare_fn(&a->data.fn, &b->data.fn);
   case TAG_IDENT: return compare_ident(&a->data.ident, &b->data.ident);
   case TAG_LIST: return compare_list(a->data.list, b->data.list);
+  case TAG_MAP: return compare_map(&a->data.map, &b->data.map);
   case TAG_PTAG: return compare_ptag(a->data.ptag, b->data.ptag);
   case TAG_QUOTE: return compare_quote(&a->data.quote, &b->data.quote);
   case TAG_STR: return compare_str(&a->data.str, &b->data.str);
diff --git a/libc3/compare.h b/libc3/compare.h
index 561908a..2504285 100644
--- a/libc3/compare.h
+++ b/libc3/compare.h
@@ -36,6 +36,7 @@ s8 compare_integer (const s_integer *a, const s_integer *b);
 s8 compare_integer_s64 (const s_integer *a, s64 b);
 s8 compare_integer_u64 (const s_integer *a, u64 b);
 s8 compare_list (const s_list *a, const s_list *b);
+s8 compare_map (const s_map *a, const s_map *b);
 s8 compare_ptag (const p_tag a, const p_tag b);
 s8 compare_quote (const s_quote *a, const s_quote *b);
 COMPARE_PROTOTYPE(s8);
diff --git a/libc3/list.c b/libc3/list.c
index 7677e9e..3f1f3c7 100644
--- a/libc3/list.c
+++ b/libc3/list.c
@@ -26,7 +26,7 @@ s_list * list_1 (const char *p)
   s_buf buf;
   s_list *list;
   buf_init_1(&buf, p);
-  if (buf_parse_list(&buf, &list) <= 0) {
+  if (buf_parse_list(&buf, &list) != (sw) strlen(p)) {
     assert(! "invalid list");
     buf_clean(&buf);
     return NULL;
diff --git a/libc3/map.c b/libc3/map.c
index 47c5f77..0905204 100644
--- a/libc3/map.c
+++ b/libc3/map.c
@@ -13,6 +13,9 @@
 #include <assert.h>
 #include <err.h>
 #include <stdlib.h>
+#include <string.h>
+#include "buf.h"
+#include "buf_parse.h"
 #include "compare.h"
 #include "list.h"
 #include "map.h"
@@ -78,6 +81,23 @@ s_map * map_init (s_map *map, uw count)
   return map;
 }
 
+s_map * map_init_1 (s_map *map, const s8 *p)
+{
+  s_buf buf;
+  sw r;
+  assert(map);
+  assert(p);
+  buf_init_1(&buf, p);
+  if ((r = buf_parse_map(&buf, map)) != (sw) strlen(p)) {
+    assert(! "invalid map");
+    warnx("invalid map: \"%s\" (%ld)", p, r);
+    buf_clean(&buf);
+    return NULL;
+  }
+  buf_clean(&buf);
+  return map;
+}
+
 s_map * map_init_from_lists (s_map *map, const s_list *keys,
                              const s_list *values)
 {
@@ -119,6 +139,16 @@ s_map * map_new (uw count)
   return map_init(map, count);
 }
 
+s_map * map_new_1 (const s8 *p)
+{
+  s_map *map;
+  if (! (map = malloc(sizeof(s_map)))) {
+    warn("map_new");
+    return NULL;
+  }
+  return map_init_1(map, p);
+}
+
 s_map * map_new_from_lists (const s_list *keys, const s_list *values)
 {
   s_map *map;
diff --git a/libc3/map.h b/libc3/map.h
index 355ea6f..9025dcc 100644
--- a/libc3/map.h
+++ b/libc3/map.h
@@ -18,12 +18,14 @@
 /* Stack allocation compatible functions, call map_clean after use. */
 void    map_clean (s_map *map);
 s_map * map_init (s_map *map, uw size);
+s_map * map_init_1 (s_map *map, const s8 *p);
 s_map * map_init_from_lists (s_map *map, const s_list *keys,
                              const s_list *values);
 
 /* Heap allocation functions, call map_delete after use. */
 void    map_delete (s_map *map);
 s_map * map_new (uw size);
+s_map * map_new_1 (const s8 *p);
 s_map * map_new_from_lists (const s_list *keys, const s_list *values);
 
 /* Modifiers */
diff --git a/test/compare_test.c b/test/compare_test.c
index ac6e338..9caf0ff 100644
--- a/test/compare_test.c
+++ b/test/compare_test.c
@@ -12,6 +12,7 @@
  */
 #include "compare_test.h"
 #include "../libc3/list.h"
+#include "../libc3/map.h"
 #include "../libc3/tag.h"
 #include "../libc3/tuple.h"
 
@@ -26,6 +27,13 @@
     test_context(NULL);                                                \
   } while (0)
 
+#define COMPARE_TEST_MAP(a, b, expected)                               \
+  do {                                                                 \
+    test_context("compare_map(" # a ", " # b ") -> " # expected);      \
+    TEST_EQ(compare_map((a), (b)), (expected));                        \
+    test_context(NULL);                                                \
+  } while (0)
+
 #define COMPARE_TEST_TAG(a, b, expected)                               \
   do {                                                                 \
     TEST_EQ(compare_tag((a), (b)), (expected));                        \
@@ -43,6 +51,7 @@ TEST_CASE_PROTOTYPE(compare_character);
 TEST_CASE_PROTOTYPE(compare_f32);
 TEST_CASE_PROTOTYPE(compare_f64);
 TEST_CASE_PROTOTYPE(compare_list);
+TEST_CASE_PROTOTYPE(compare_map);
 TEST_CASE_PROTOTYPE(compare_str);
 TEST_CASE_PROTOTYPE(compare_tag);
 TEST_CASE_PROTOTYPE(compare_tuple);
@@ -54,6 +63,7 @@ void compare_test (void)
   TEST_CASE_RUN(compare_f32);
   TEST_CASE_RUN(compare_f64);
   TEST_CASE_RUN(compare_list);
+  TEST_CASE_RUN(compare_map);
   TEST_CASE_RUN(compare_str);
   TEST_CASE_RUN(compare_tag);
   TEST_CASE_RUN(compare_tuple);
@@ -145,6 +155,34 @@ TEST_CASE(compare_list)
 }
 TEST_CASE_END(compare_list)
 
+TEST_CASE(compare_map)
+{
+  s_map a;
+  s_map b;
+  COMPARE_TEST_MAP(map_init_1(&a, "%{a: A, b: B}"),
+                   map_init_1(&b, "%{a: A, b: B}"), 0);
+  COMPARE_TEST_MAP(&a, &a, 0);
+  map_clean(&a);
+  map_clean(&b);
+  COMPARE_TEST_MAP(map_init_1(&a, "%{a: A, b: A}"),
+                   map_init_1(&b, "%{a: A, b: B}"), -1);
+  map_clean(&a);
+  map_clean(&b);
+  COMPARE_TEST_MAP(map_init_1(&a, "%{a: A, b: B}"),
+                   map_init_1(&b, "%{a: A, b: A}"), 1);
+  map_clean(&a);
+  map_clean(&b);
+  COMPARE_TEST_MAP(map_init_1(&a, "%{a: A, b: B}"),
+                   map_init_1(&b, "%{a: A, b: B, c: C}"), -1);
+  map_clean(&a);
+  map_clean(&b);
+  COMPARE_TEST_MAP(map_init_1(&a, "%{a: A, b: B, c: C}"),
+                   map_init_1(&b, "%{a: A, b: B}"), 1);
+  map_clean(&a);
+  map_clean(&b);
+}
+TEST_CASE_END(compare_map)
+
 TEST_CASE(compare_str)
 {
   s_str *p;
diff --git a/test/compare_test.h b/test/compare_test.h
index 2c6c907..fa663d3 100644
--- a/test/compare_test.h
+++ b/test/compare_test.h
@@ -19,21 +19,22 @@
 
 #define COMPARE_TEST_STR(a, b, expected)                               \
   do {                                                                 \
-    const s_str *a_ = (a);                                                   \
-    const s_str *b_ = (b);                                                   \
+    const s_str *a_ = (a);                                             \
+    const s_str *b_ = (b);                                             \
     sw tmp = compare_str(a_, b_);                                      \
     if (tmp == expected) {                                             \
-      test_ok();                                                       \
+      g_test_assert_count++;                                           \
+      g_test_assert_ok++;                                              \
     }                                                                  \
     else {                                                             \
       test_ko();                                                       \
-      printf("\n%sAssertion failed in %s:%d %s\n"                      \
-             "compare_str(%s, %s) == %s\n"                             \
-             "Expected %s got %ld.%s\n",                               \
-             TEST_COLOR_KO,                                            \
-             __FILE__, __LINE__, __func__,                             \
-             # a, # b, # expected, # expected, tmp,                    \
-             TEST_COLOR_RESET);                                        \
+      fprintf(stderr, "\n%sAssertion failed in %s:%d %s\n"             \
+              "compare_str(%s, %s) == %s\n"                            \
+              "Expected %s got %ld.%s\n",                              \
+              TEST_COLOR_KO,                                           \
+              __FILE__, __LINE__, __func__,                            \
+              # a, # b, # expected, # expected, tmp,                   \
+              TEST_COLOR_RESET);                                       \
     }                                                                  \
   } while (0)
 
diff --git a/test/ic3/map.in b/test/ic3/map.in
index 6eb013e..61f071f 100644
--- a/test/ic3/map.in
+++ b/test/ic3/map.in
@@ -50,3 +50,33 @@ quote %{b: b} = %{a: 1, b: 2}
 %{b: b} = %{a: 1, b: 2}
 quote b
 b
+quote %{a: A, b: A} < %{a: A, b: A}
+%{a: A, b: A} < %{a: A, b: A}
+quote %{a: A, b: A} < %{a: A, c: A}
+%{a: A, b: A} < %{a: A, c: A}
+quote %{a: A, c: A} < %{a: A, b: A}
+%{a: A, c: A} < %{a: A, b: A}
+quote %{a: A, b: A} < %{a: A, b: B}
+%{a: A, b: A} < %{a: A, b: B}
+quote %{a: B, b: A} < %{a: A, b: A}
+%{a: B, b: A} < %{a: A, b: A}
+quote %{a: A, b: A} == %{a: A, b: A}
+%{a: A, b: A} == %{a: A, b: A}
+quote %{a: A, b: A} == %{a: A, c: A}
+%{a: A, b: A} == %{a: A, c: A}
+quote %{a: A, c: A} == %{a: A, b: A}
+%{a: A, c: A} == %{a: A, b: A}
+quote %{a: A, b: A} == %{a: A, b: B}
+%{a: A, b: A} == %{a: A, b: B}
+quote %{a: B, b: A} == %{a: A, b: A}
+%{a: B, b: A} == %{a: A, b: A}
+quote %{a: A, b: A} > %{a: A, b: A}
+%{a: A, b: A} > %{a: A, b: A}
+quote %{a: A, b: A} > %{a: A, c: A}
+%{a: A, b: A} > %{a: A, c: A}
+quote %{a: A, c: A} > %{a: A, b: A}
+%{a: A, c: A} > %{a: A, b: A}
+quote %{a: A, b: A} > %{a: A, b: B}
+%{a: A, b: A} > %{a: A, b: B}
+quote %{a: B, b: A} > %{a: A, b: A}
+%{a: B, b: A} > %{a: A, b: A}
diff --git a/test/ic3/map.out.expected b/test/ic3/map.out.expected
index 0cbf8ab..4deb429 100644
--- a/test/ic3/map.out.expected
+++ b/test/ic3/map.out.expected
@@ -50,3 +50,33 @@ a
 %{a: 1, b: 2}
 b
 2
+%{a: A, b: A} < %{a: A, b: A}
+false
+%{a: A, b: A} < %{a: A, c: A}
+true
+%{a: A, c: A} < %{a: A, b: A}
+false
+%{a: A, b: A} < %{a: A, b: B}
+true
+%{a: B, b: A} < %{a: A, b: A}
+false
+%{a: A, b: A} == %{a: A, b: A}
+true
+%{a: A, b: A} == %{a: A, c: A}
+false
+%{a: A, c: A} == %{a: A, b: A}
+false
+%{a: A, b: A} == %{a: A, b: B}
+false
+%{a: B, b: A} == %{a: A, b: A}
+false
+%{a: A, b: A} > %{a: A, b: A}
+false
+%{a: A, b: A} > %{a: A, c: A}
+false
+%{a: A, c: A} > %{a: A, b: A}
+true
+%{a: A, b: A} > %{a: A, b: B}
+false
+%{a: B, b: A} > %{a: A, b: A}
+true