From caeea720b52252bc37f1e60bf546333bfe3c2cf8 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Wed, 5 Mar 2014 20:24:35 +0100
Subject: erl_interface: refactor ei_decode_encode_test.c
to prepare for lists, tuples and ... maps!
---
.../ei_decode_encode_test.c | 345 ++++++++++++---------
1 file changed, 207 insertions(+), 138 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 317e5edecd..3e32be8087 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -32,9 +32,28 @@
/*#define MESSAGE(FMT,A1,A2) message(FMT,A1,A2)*/
#define MESSAGE(FMT,A1,A2)
-typedef int decodeFT(const char *buf, int *index, void*);
-typedef int encodeFT(char *buf, int *index, void*);
-typedef int x_encodeFT(ei_x_buff*, void*);
+
+typedef struct
+{
+ char name[MAXATOMLEN_UTF8];
+ erlang_char_encoding enc;
+}my_atom;
+
+union my_obj {
+ erlang_fun fun;
+ erlang_pid pid;
+ erlang_port port;
+ erlang_ref ref;
+ erlang_trace trace;
+ erlang_big big;
+ my_atom atom;
+
+ int arity;
+};
+
+typedef int decodeFT(const char *buf, int *index, union my_obj*);
+typedef int encodeFT(char *buf, int *index, union my_obj*);
+typedef int x_encodeFT(ei_x_buff*, union my_obj*);
struct Type {
char* name;
@@ -44,11 +63,36 @@ struct Type {
x_encodeFT* ei_x_encode_fp;
};
-typedef struct
-{
- char name[MAXATOMLEN_UTF8];
- erlang_char_encoding enc;
-}my_atom;
+
+struct Type fun_type = {
+ "fun", "erlang_fun", (decodeFT*)ei_decode_fun,
+ (encodeFT*)ei_encode_fun, (x_encodeFT*)ei_x_encode_fun
+};
+
+struct Type pid_type = {
+ "pid", "erlang_pid", (decodeFT*)ei_decode_pid,
+ (encodeFT*)ei_encode_pid, (x_encodeFT*)ei_x_encode_pid
+};
+
+struct Type port_type = {
+ "port", "erlang_port", (decodeFT*)ei_decode_port,
+ (encodeFT*)ei_encode_port, (x_encodeFT*)ei_x_encode_port
+};
+
+struct Type ref_type = {
+ "ref", "erlang_ref", (decodeFT*)ei_decode_ref,
+ (encodeFT*)ei_encode_ref, (x_encodeFT*)ei_x_encode_ref
+};
+
+struct Type trace_type = {
+ "trace", "erlang_trace", (decodeFT*)ei_decode_trace,
+ (encodeFT*)ei_encode_trace, (x_encodeFT*)ei_x_encode_trace
+};
+
+struct Type big_type = {
+ "big", "erlang_big", (decodeFT*)ei_decode_big,
+ (encodeFT*)ei_encode_big, (x_encodeFT*)ei_x_encode_big
+};
int ei_decode_my_atom(const char *buf, int *index, my_atom* a)
{
@@ -64,130 +108,163 @@ int ei_x_encode_my_atom(ei_x_buff* x, my_atom* a)
return ei_x_encode_atom_as(x, a->name, ERLANG_UTF8, a->enc);
}
+struct Type my_atom_type = {
+ "atom", "my_atom", (decodeFT*)ei_decode_my_atom,
+ (encodeFT*)ei_encode_my_atom, (x_encodeFT*)ei_x_encode_my_atom
+};
+
+
+int my_encode_tuple_header(char *buf, int *index, union my_obj* obj)
+{
+ return ei_encode_tuple_header(buf, index, obj->arity);
+}
+int my_x_encode_tuple_header(ei_x_buff* x, union my_obj* obj)
+{
+ return ei_x_encode_tuple_header(x, (long)obj->arity);
+}
+
+struct Type tuple_type = {
+ "tuple_header", "arity", (decodeFT*)ei_decode_tuple_header,
+ my_encode_tuple_header, my_x_encode_tuple_header
+};
+
#define BUFSZ 2000
-void decode_encode(struct Type* t, void* obj)
+void decode_encode(struct Type** tv, int nobj)
{
- char *buf;
- char buf2[BUFSZ];
- int size1 = 0;
- int size2 = 0;
- int size3 = 0;
- int err;
+ union my_obj obj;
+ char* packet;
+ char* inp;
+ char* outp;
+ char out_buf[BUFSZ];
+ int size1, size2, size3;
+ int err, i;
ei_x_buff arg;
- MESSAGE("ei_decode_%s, arg is type %s", t->name, t->type);
- buf = read_packet(NULL);
- err = t->ei_decode_fp(buf+1, &size1, NULL);
- if (err != 0) {
- if (err != -1) {
- fail("decode returned non zero but not -1");
- } else {
- fail("decode returned non zero");
+ packet = read_packet(NULL);
+ inp = packet+1;
+ outp = out_buf;
+ ei_x_new(&arg);
+ for (i=0; iname, t->type);
+
+ size1 = 0;
+ err = t->ei_decode_fp(inp, &size1, NULL);
+ if (err != 0) {
+ if (err != -1) {
+ fail("decode returned non zero but not -1");
+ } else {
+ fail("decode returned non zero");
+ }
+ return;
+ }
+ if (size1 < 1) {
+ fail("size is < 1");
+ return;
}
- return;
- }
- if (size1 < 1) {
- fail("size is < 1");
- return;
- }
- if (size1 > BUFSZ) {
- fail("size is > BUFSZ");
- return;
- }
+ if (size1 > BUFSZ) {
+ fail("size is > BUFSZ");
+ return;
+ }
- err = t->ei_decode_fp(buf+1, &size2, obj);
- if (err != 0) {
- if (err != -1) {
- fail("decode returned non zero but not -1");
- } else {
- fail("decode returned non zero");
+ size2 = 0;
+ err = t->ei_decode_fp(inp, &size2, &obj);
+ if (err != 0) {
+ if (err != -1) {
+ fail("decode returned non zero but not -1");
+ } else {
+ fail("decode returned non zero");
+ }
+ return;
+ }
+ if (size1 != size2) {
+ MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
+ fail("decode sizes differs");
+ return;
}
- return;
- }
- if (size1 != size2) {
- MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
- fail("decode sizes differs");
- return;
- }
- size2 = 0;
- err = ei_skip_term(buf+1, &size2);
- if (err != 0) {
- fail("ei_skip_term returned non zero");
- return;
- }
- if (size1 != size2) {
- MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
- fail("skip size differs");
- return;
- }
+ if (t != &tuple_type) {
+ size2 = 0;
+ err = ei_skip_term(inp, &size2);
+ if (err != 0) {
+ fail("ei_skip_term returned non zero");
+ return;
+ }
+ if (size1 != size2) {
+ MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
+ fail("skip size differs");
+ return;
+ }
+ }
- MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type);
- size2 = 0;
- err = t->ei_encode_fp(NULL, &size2, obj);
- if (err != 0) {
- if (err != -1) {
- fail("size calculation returned non zero but not -1");
+ MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type);
+ size2 = 0;
+ err = t->ei_encode_fp(NULL, &size2, &obj);
+ if (err != 0) {
+ if (err != -1) {
+ fail("size calculation returned non zero but not -1");
+ return;
+ } else {
+ fail("size calculation returned non zero");
+ return;
+ }
+ }
+ if (size1 != size2) {
+ MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
+ fail("decode and encode size differs when buf is NULL");
return;
- } else {
- fail("size calculation returned non zero");
+ }
+ MESSAGE("ei_encode_%s, arg is type %s", t->name, t->type);
+ size3 = 0;
+ err = t->ei_encode_fp(outp, &size3, &obj);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1");
+ } else {
+ fail("returned non zero");
+ }
return;
}
- }
- if (size1 != size2) {
- MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
- fail("decode and encode size differs when buf is NULL");
- return;
- }
- MESSAGE("ei_encode_%s, arg is type %s", t->name, t->type);
- err = t->ei_encode_fp(buf2, &size3, obj);
- if (err != 0) {
- if (err != -1) {
- fail("returned non zero but not -1");
- } else {
- fail("returned non zero");
+ if (size1 != size3) {
+ MESSAGE("size1 = %d, size2 = %d\n",size1,size3);
+ fail("decode and encode size differs");
+ return;
}
- return;
- }
- if (size1 != size3) {
- MESSAGE("size1 = %d, size2 = %d\n",size1,size3);
- fail("decode and encode size differs");
- return;
- }
- send_buffer(buf2, size1);
- MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type);
- ei_x_new(&arg);
- err = t->ei_x_encode_fp(&arg, obj);
- if (err != 0) {
- if (err != -1) {
- fail("returned non zero but not -1");
- } else {
- fail("returned non zero");
+ MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type);
+ err = t->ei_x_encode_fp(&arg, &obj);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1");
+ } else {
+ fail("returned non zero");
+ }
+ ei_x_free(&arg);
+ return;
}
- ei_x_free(&arg);
- return;
- }
- if (arg.index < 1) {
- fail("size is < 1");
- ei_x_free(&arg);
- return;
+ if (arg.index < 1) {
+ fail("size is < 1");
+ ei_x_free(&arg);
+ return;
+ }
+
+ inp += size1;
+ outp += size1;
}
+ send_buffer(out_buf, outp - out_buf);
send_buffer(arg.buff, arg.index);
ei_x_free(&arg);
+ free(packet);
}
+void decode_encode_one(struct Type* t)
+{
+ decode_encode(&t, 1);
+}
-#define EI_DECODE_ENCODE(TYPE, ERLANG_TYPE) { \
- struct Type type_struct = {#TYPE, #ERLANG_TYPE, \
- (decodeFT*)ei_decode_##TYPE, \
- (encodeFT*)ei_encode_##TYPE, \
- (x_encodeFT*)ei_x_encode_##TYPE }; \
- ERLANG_TYPE type_obj; \
- decode_encode(&type_struct, &type_obj); \
- }
void decode_encode_big(struct Type* t)
@@ -274,14 +351,6 @@ void decode_encode_big(struct Type* t)
ei_free_big(p);
}
-#define EI_DECODE_ENCODE_BIG(TYPE, ERLANG_TYPE) { \
- struct Type type_struct = {#TYPE, #ERLANG_TYPE, \
- (decodeFT*)ei_decode_##TYPE, \
- (encodeFT*)ei_encode_##TYPE, \
- (x_encodeFT*)ei_x_encode_##TYPE }; \
- decode_encode_big(&type_struct); \
- }
-
/* ******************************************************************** */
@@ -290,34 +359,34 @@ TESTCASE(test_ei_decode_encode)
{
int i;
- EI_DECODE_ENCODE(fun , erlang_fun);
- EI_DECODE_ENCODE(pid , erlang_pid);
- EI_DECODE_ENCODE(port , erlang_port);
- EI_DECODE_ENCODE(ref , erlang_ref);
- EI_DECODE_ENCODE(trace, erlang_trace);
+ decode_encode_one(&fun_type);
+ decode_encode_one(&pid_type);
+ decode_encode_one(&port_type);
+ decode_encode_one(&ref_type);
+ decode_encode_one(&trace_type);
- EI_DECODE_ENCODE_BIG(big , erlang_big);
- EI_DECODE_ENCODE_BIG(big , erlang_big);
- EI_DECODE_ENCODE_BIG(big , erlang_big);
+ decode_encode_big(&big_type);
+ decode_encode_big(&big_type);
+ decode_encode_big(&big_type);
- EI_DECODE_ENCODE_BIG(big , erlang_big);
- EI_DECODE_ENCODE_BIG(big , erlang_big);
- EI_DECODE_ENCODE_BIG(big , erlang_big);
+ decode_encode_big(&big_type);
+ decode_encode_big(&big_type);
+ decode_encode_big(&big_type);
/* Test large node containers... */
- EI_DECODE_ENCODE(pid , erlang_pid);
- EI_DECODE_ENCODE(port , erlang_port);
- EI_DECODE_ENCODE(ref , erlang_ref);
- EI_DECODE_ENCODE(pid , erlang_pid);
- EI_DECODE_ENCODE(port , erlang_port);
- EI_DECODE_ENCODE(ref , erlang_ref);
+ decode_encode_one(&pid_type);
+ decode_encode_one(&port_type);
+ decode_encode_one(&ref_type);
+ decode_encode_one(&pid_type);
+ decode_encode_one(&port_type);
+ decode_encode_one(&ref_type);
/* Unicode atoms */
for (i=0; i<24; i++) {
- EI_DECODE_ENCODE(my_atom, my_atom);
- EI_DECODE_ENCODE(pid, erlang_pid);
- EI_DECODE_ENCODE(port, erlang_port);
- EI_DECODE_ENCODE(ref, erlang_ref);
+ decode_encode_one(&my_atom_type);
+ decode_encode_one(&pid_type);
+ decode_encode_one(&port_type);
+ decode_encode_one(&ref_type);
}
report(1);
--
cgit v1.2.3
From 453cba0046ec8363a4c3cea97ce22a6f4ff0b75a Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Thu, 6 Mar 2014 12:25:05 +0100
Subject: erl_interface: test decode_encode of tuples and lists
---
lib/erl_interface/test/ei_decode_encode_SUITE.erl | 7 ++-
.../ei_decode_encode_test.c | 59 +++++++++++++++++++++-
2 files changed, 63 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index c7830f58f2..b0952d4b04 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -127,6 +127,11 @@ test_ei_decode_encode(Config) when is_list(Config) ->
send_rec(P, mk_ref({Atom,1}, [262143, 8723648, 24097245])),
void
end || Atom <- unicode_atom_data()],
+
+ send_rec(P, {}),
+ send_rec(P, {atom, Pid, Port, Ref}),
+ send_rec(P, [atom, Pid, Port, Ref]),
+ send_rec(P, [atom | Fun]),
?line runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 3e32be8087..9a50aef7b6 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -128,6 +128,45 @@ struct Type tuple_type = {
my_encode_tuple_header, my_x_encode_tuple_header
};
+int my_encode_list_header(char *buf, int *index, union my_obj* obj)
+{
+ return ei_encode_list_header(buf, index, obj->arity);
+}
+int my_x_encode_list_header(ei_x_buff* x, union my_obj* obj)
+{
+ return ei_x_encode_list_header(x, (long)obj->arity);
+}
+
+struct Type list_type = {
+ "list_header", "arity", (decodeFT*)ei_decode_list_header,
+ my_encode_list_header, my_x_encode_list_header
+};
+
+
+int my_decode_nil(const char *buf, int *index, union my_obj* dummy)
+{
+ int type, size, ret;
+ ret = ei_get_type(buf, index, &type, &size);
+ (*index)++;
+ return ret ? ret : !(type == ERL_NIL_EXT);
+
+}
+int my_encode_nil(char *buf, int *index, union my_obj* dummy)
+{
+ return ei_encode_empty_list(buf, index);
+}
+
+int my_x_encode_nil(ei_x_buff* x, union my_obj* dummy)
+{
+ return ei_x_encode_empty_list(x);
+}
+
+struct Type nil_type = {
+ "empty_list", "nil", (decodeFT*)my_decode_nil,
+ my_encode_nil, my_x_encode_nil
+};
+
+
#define BUFSZ 2000
void decode_encode(struct Type** tv, int nobj)
@@ -186,7 +225,7 @@ void decode_encode(struct Type** tv, int nobj)
return;
}
- if (t != &tuple_type) {
+ if (t != &tuple_type && t != &list_type) {
size2 = 0;
err = ei_skip_term(inp, &size2);
if (err != 0) {
@@ -389,6 +428,22 @@ TESTCASE(test_ei_decode_encode)
decode_encode_one(&ref_type);
}
+ decode_encode_one(&tuple_type); /* {} */
+ {
+ struct Type* tpl[] = { &tuple_type, &my_atom_type, &pid_type, &port_type, &ref_type };
+ decode_encode(tpl, 5);
+ }
+
+ {
+ struct Type* list[] = { &list_type, &my_atom_type, &pid_type, &port_type, &ref_type, &nil_type };
+ decode_encode(list, 6);
+ }
+ {
+ struct Type* list[] = { &list_type, &my_atom_type, &fun_type };
+ decode_encode(list, 3);
+ }
+
+
report(1);
}
--
cgit v1.2.3
From 6941af88ad016141f568279f065cb181074f1f9f Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Thu, 6 Mar 2014 15:13:34 +0100
Subject: erl_interface: Add ei encode/decode for maps
---
lib/erl_interface/doc/src/ei.xml | 36 +++++++++++++++++++++-
lib/erl_interface/include/ei.h | 6 +++-
lib/erl_interface/src/decode/decode_tuple_header.c | 23 +++++++++++++-
lib/erl_interface/src/encode/encode_tuple_header.c | 19 +++++++++++-
lib/erl_interface/src/misc/ei_decode_term.c | 3 +-
lib/erl_interface/src/misc/ei_x_encode.c | 12 +++++++-
6 files changed, 93 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml
index ab185c9179..1756ee8a7d 100644
--- a/lib/erl_interface/doc/src/ei.xml
+++ b/lib/erl_interface/doc/src/ei.xml
@@ -4,7 +4,7 @@
- 20012013
+ 20012014
Ericsson AB. All Rights Reserved.
@@ -416,6 +416,27 @@ ei_x_encode_empty_list(&x);
tail of a list.
+
+ intei_encode_map_header(char *buf, int *index, int arity)
+ intei_x_encode_map_header(ei_x_buff* x, int arity)
+ Encode a map
+
+ This function encodes a map header, with a specified arity. The next
+ arity terms encoded will be the keys of the map, and the next
+ arity terms after that will be the corresponding values in
+ same order.
+ E.g. to encode the map #{a => "Apple", b => "Banana"}:
+
+ei_x_encode_map_header(&x, 2);
+ei_x_encode_atom(&x, "a");
+ei_x_encode_atom(&x, "b");
+ei_x_encode_string(&x, "Apple");
+ei_x_encode_string(&x, "Banana");
+
+ A correctly encoded map can not have duplicate keys, but no check
+ for duplicate keys is done by this function.
+
+
intei_get_type(const char *buf, const int *index, int *type, int *size)
Fetch the type and size of an encoded term
@@ -637,6 +658,19 @@ ei_x_encode_empty_list(&x);
instead.
+
+ intei_decode_map_header(const char *buf, int *index, int *arity)
+ Decode a map
+
+ This function decodes a map header from the binary
+ format. The number of key-value pairs is returned in
+ arity. Keys and values follows, first all keys and then all values,
+ which makes a total of arity*2 terms.
+ Keys and values are paired according to their order, the first key
+ with the first value and so on. If arity is zero, it's an empty map.
+ A correctly encoded map does not have duplicate keys.
+
+
intei_decode_ei_term(const char* buf, int* index, ei_term* term)
Decode a term, without prior knowledge of type
diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h
index 9b83385a46..a3eb437f88 100644
--- a/lib/erl_interface/include/ei.h
+++ b/lib/erl_interface/include/ei.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -131,6 +131,7 @@
#define ERL_SMALL_BIG_EXT 'n'
#define ERL_LARGE_BIG_EXT 'o'
#define ERL_NEW_FUN_EXT 'p'
+#define ERL_MAP_EXT 't'
#define ERL_FUN_EXT 'u'
#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */
@@ -467,6 +468,8 @@ int ei_encode_list_header(char *buf, int *index, int arity);
int ei_x_encode_list_header(ei_x_buff* x, long n);
#define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0)
int ei_x_encode_empty_list(ei_x_buff* x);
+int ei_encode_map_header(char *buf, int *index, int arity);
+int ei_x_encode_map_header(ei_x_buff* x, long n);
/*
* ei_get_type() returns the type and "size" of the item at
@@ -507,6 +510,7 @@ int ei_decode_term(const char *buf, int *index, void *t); /* ETERM** actually */
int ei_decode_trace(const char *buf, int *index, erlang_trace *p);
int ei_decode_tuple_header(const char *buf, int *index, int *arity);
int ei_decode_list_header(const char *buf, int *index, int *arity);
+int ei_decode_map_header(const char *buf, int *index, int *arity);
/*
* ei_decode_ei_term() returns 1 if term is decoded, 0 if term is OK,
diff --git a/lib/erl_interface/src/decode/decode_tuple_header.c b/lib/erl_interface/src/decode/decode_tuple_header.c
index c0ba14ea47..698be1b97a 100644
--- a/lib/erl_interface/src/decode/decode_tuple_header.c
+++ b/lib/erl_interface/src/decode/decode_tuple_header.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -45,3 +45,24 @@ int ei_decode_tuple_header(const char *buf, int *index, int *arity)
return 0;
}
+
+int ei_decode_map_header(const char *buf, int *index, int *arity)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int i;
+
+ switch ((i=get8(s))) {
+ case ERL_MAP_EXT:
+ if (arity) *arity = get32be(s);
+ else s += 4;
+ break;
+
+ default:
+ return -1;
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/encode/encode_tuple_header.c b/lib/erl_interface/src/encode/encode_tuple_header.c
index 97a3d1f808..5b11e60447 100644
--- a/lib/erl_interface/src/encode/encode_tuple_header.c
+++ b/lib/erl_interface/src/encode/encode_tuple_header.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -47,3 +47,20 @@ int ei_encode_tuple_header(char *buf, int *index, int arity)
return 0;
}
+int ei_encode_map_header(char *buf, int *index, int arity)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (arity < 0) return -1;
+
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_MAP_EXT);
+ put32be(s,arity);
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c
index ce5ae5b19d..2e7317f781 100644
--- a/lib/erl_interface/src/misc/ei_decode_term.c
+++ b/lib/erl_interface/src/misc/ei_decode_term.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -100,6 +100,7 @@ int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
term->size = get16be(s);
return 0;
case ERL_LIST_EXT:
+ case ERL_MAP_EXT:
term->arity = get32be(s);
break;
case ERL_BINARY_EXT:
diff --git a/lib/erl_interface/src/misc/ei_x_encode.c b/lib/erl_interface/src/misc/ei_x_encode.c
index 14d0b56b8f..10542c88a5 100644
--- a/lib/erl_interface/src/misc/ei_x_encode.c
+++ b/lib/erl_interface/src/misc/ei_x_encode.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -206,6 +206,16 @@ int ei_x_encode_tuple_header(ei_x_buff* x, long n)
return ei_encode_tuple_header(x->buff, &x->index, n);
}
+int ei_x_encode_map_header(ei_x_buff* x, long n)
+{
+ int i = x->index;
+ if (ei_encode_map_header(NULL, &i, n) == -1)
+ return -1;
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_map_header(x->buff, &x->index, n);
+}
+
int ei_x_encode_atom(ei_x_buff* x, const char* s)
{
return ei_x_encode_atom_len_as(x, s, strlen(s), ERLANG_LATIN1, ERLANG_LATIN1);
--
cgit v1.2.3
From 78796d03ac341da53e9c8b7f8d69cc3c0a949c14 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Thu, 6 Mar 2014 16:17:09 +0100
Subject: erl_interface: test decode/encode of maps
---
lib/erl_interface/test/ei_decode_encode_SUITE.erl | 4 ++++
.../ei_decode_encode_test.c | 28 +++++++++++++++++++++-
2 files changed, 31 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index b0952d4b04..7caec6ac04 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -132,6 +132,10 @@ test_ei_decode_encode(Config) when is_list(Config) ->
send_rec(P, {atom, Pid, Port, Ref}),
send_rec(P, [atom, Pid, Port, Ref]),
send_rec(P, [atom | Fun]),
+ send_rec(P, #{}),
+ send_rec(P, #{key => value}),
+ send_rec(P, maps:put(Port, Ref, #{key => value, key2 => Pid})),
+
?line runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 9a50aef7b6..1ef17d4161 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -166,6 +166,20 @@ struct Type nil_type = {
my_encode_nil, my_x_encode_nil
};
+int my_encode_map_header(char *buf, int *index, union my_obj* obj)
+{
+ return ei_encode_map_header(buf, index, obj->arity);
+}
+int my_x_encode_map_header(ei_x_buff* x, union my_obj* obj)
+{
+ return ei_x_encode_map_header(x, (long)obj->arity);
+}
+
+struct Type map_type = {
+ "map_header", "arity", (decodeFT*)ei_decode_map_header,
+ my_encode_map_header, my_x_encode_map_header
+};
+
#define BUFSZ 2000
@@ -225,7 +239,7 @@ void decode_encode(struct Type** tv, int nobj)
return;
}
- if (t != &tuple_type && t != &list_type) {
+ if (t != &tuple_type && t != &list_type && t != &map_type) {
size2 = 0;
err = ei_skip_term(inp, &size2);
if (err != 0) {
@@ -442,7 +456,19 @@ TESTCASE(test_ei_decode_encode)
struct Type* list[] = { &list_type, &my_atom_type, &fun_type };
decode_encode(list, 3);
}
+ decode_encode_one(&map_type); /* #{} */
+ { /* #{atom => atom}*/
+ struct Type* map[] = { &map_type, &my_atom_type, &my_atom_type };
+ decode_encode(map, 3);
+ }
+ { /* #{atom => atom, atom => pid, port => ref }*/
+ struct Type* map[] = { &map_type,
+ &my_atom_type, &my_atom_type, &port_type,
+ &my_atom_type, &pid_type, &ref_type
+ };
+ decode_encode(map, 7);
+ }
report(1);
}
--
cgit v1.2.3
From dbdf33a57b8e92fc9a45029ed3fef0f70c852909 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Mon, 10 Mar 2014 20:19:58 +0100
Subject: erl_interface: Fix mem leak in ei_decode_encode_test
---
lib/erl_interface/test/all_SUITE_data/ei_runner.c | 6 +++++-
lib/erl_interface/test/all_SUITE_data/ei_runner.h | 3 ++-
.../test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c | 2 +-
3 files changed, 8 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.c b/lib/erl_interface/test/all_SUITE_data/ei_runner.c
index cdf32b48c4..196a77dce5 100644
--- a/lib/erl_interface/test/all_SUITE_data/ei_runner.c
+++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -182,6 +182,10 @@ char *read_packet(int *len)
return io_buf;
}
+void free_packet(char* packet)
+{
+ free(packet);
+}
/***********************************************************************
* S e n d i n g r e p l i e s
diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.h b/lib/erl_interface/test/all_SUITE_data/ei_runner.h
index 96d6a1cbf7..a037341d57 100644
--- a/lib/erl_interface/test/all_SUITE_data/ei_runner.h
+++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -44,6 +44,7 @@ void run_tests(char* argv0, TestCase cases[], unsigned number);
int get_bin_term(ei_x_buff* x, ei_term* term);
char *read_packet(int *len);
+void free_packet(char*);
/*
* Sending replies.
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 1ef17d4161..649138b471 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -310,7 +310,7 @@ void decode_encode(struct Type** tv, int nobj)
send_buffer(out_buf, outp - out_buf);
send_buffer(arg.buff, arg.index);
ei_x_free(&arg);
- free(packet);
+ free_packet(packet);
}
void decode_encode_one(struct Type* t)
--
cgit v1.2.3
From e5f5346c5c6d7cd7f5c68b523970c542bccd9aff Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Mon, 10 Mar 2014 20:21:08 +0100
Subject: erl_interface: Add map support in ei_skip_term
---
lib/erl_interface/src/decode/decode_skip.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c
index 553266471c..2260394da1 100644
--- a/lib/erl_interface/src/decode/decode_skip.c
+++ b/lib/erl_interface/src/decode/decode_skip.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -61,7 +61,13 @@ int ei_skip_term(const char* buf, int* index)
break;
case ERL_SMALL_TUPLE_EXT:
case ERL_LARGE_TUPLE_EXT:
- if (ei_decode_tuple_header(buf, index, &n) < 0) return -1;
+ if (ei_decode_tuple_header(buf, index, &n) < 0) return -1;
+ for (i = 0; i < n; ++i)
+ ei_skip_term(buf, index);
+ break;
+ case ERL_MAP_EXT:
+ if (ei_decode_map_header(buf, index, &n) < 0) return -1;
+ n *= 2;
for (i = 0; i < n; ++i)
ei_skip_term(buf, index);
break;
--
cgit v1.2.3
From 726271d2307c2987c06075253646875815719733 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Mon, 10 Mar 2014 20:30:11 +0100
Subject: erl_interface: Add test for ei_skip_term of container terms
---
.../ei_decode_encode_test.c | 139 +++++++++++++++------
1 file changed, 101 insertions(+), 38 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 649138b471..790d498a1d 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -39,21 +39,26 @@ typedef struct
erlang_char_encoding enc;
}my_atom;
-union my_obj {
- erlang_fun fun;
- erlang_pid pid;
- erlang_port port;
- erlang_ref ref;
- erlang_trace trace;
- erlang_big big;
- my_atom atom;
-
- int arity;
+struct my_obj {
+ union {
+ erlang_fun fun;
+ erlang_pid pid;
+ erlang_port port;
+ erlang_ref ref;
+ erlang_trace trace;
+ erlang_big big;
+ my_atom atom;
+
+ int arity;
+ }u;
+
+ int nterms; /* 0 for non-containers */
+ char* startp; /* container start position in decode buffer */
};
-typedef int decodeFT(const char *buf, int *index, union my_obj*);
-typedef int encodeFT(char *buf, int *index, union my_obj*);
-typedef int x_encodeFT(ei_x_buff*, union my_obj*);
+typedef int decodeFT(const char *buf, int *index, struct my_obj*);
+typedef int encodeFT(char *buf, int *index, struct my_obj*);
+typedef int x_encodeFT(ei_x_buff*, struct my_obj*);
struct Type {
char* name;
@@ -114,36 +119,53 @@ struct Type my_atom_type = {
};
-int my_encode_tuple_header(char *buf, int *index, union my_obj* obj)
+int my_decode_tuple_header(const char *buf, int *index, struct my_obj* obj)
{
- return ei_encode_tuple_header(buf, index, obj->arity);
+ int ret = ei_decode_tuple_header(buf, index, &obj->u.arity);
+ if (ret == 0 && obj)
+ obj->nterms = obj->u.arity;
+ return ret;
}
-int my_x_encode_tuple_header(ei_x_buff* x, union my_obj* obj)
+
+int my_encode_tuple_header(char *buf, int *index, struct my_obj* obj)
+{
+ return ei_encode_tuple_header(buf, index, obj->u.arity);
+}
+int my_x_encode_tuple_header(ei_x_buff* x, struct my_obj* obj)
{
- return ei_x_encode_tuple_header(x, (long)obj->arity);
+ return ei_x_encode_tuple_header(x, (long)obj->u.arity);
}
struct Type tuple_type = {
- "tuple_header", "arity", (decodeFT*)ei_decode_tuple_header,
+ "tuple_header", "arity", my_decode_tuple_header,
my_encode_tuple_header, my_x_encode_tuple_header
};
-int my_encode_list_header(char *buf, int *index, union my_obj* obj)
+
+int my_decode_list_header(const char *buf, int *index, struct my_obj* obj)
{
- return ei_encode_list_header(buf, index, obj->arity);
+ int ret = ei_decode_list_header(buf, index, &obj->u.arity);
+ if (ret == 0 && obj) {
+ obj->nterms = obj->u.arity + 1;
+ }
+ return ret;
+}
+int my_encode_list_header(char *buf, int *index, struct my_obj* obj)
+{
+ return ei_encode_list_header(buf, index, obj->u.arity);
}
-int my_x_encode_list_header(ei_x_buff* x, union my_obj* obj)
+int my_x_encode_list_header(ei_x_buff* x, struct my_obj* obj)
{
- return ei_x_encode_list_header(x, (long)obj->arity);
+ return ei_x_encode_list_header(x, (long)obj->u.arity);
}
struct Type list_type = {
- "list_header", "arity", (decodeFT*)ei_decode_list_header,
+ "list_header", "arity", my_decode_list_header,
my_encode_list_header, my_x_encode_list_header
};
-int my_decode_nil(const char *buf, int *index, union my_obj* dummy)
+int my_decode_nil(const char *buf, int *index, struct my_obj* dummy)
{
int type, size, ret;
ret = ei_get_type(buf, index, &type, &size);
@@ -151,32 +173,39 @@ int my_decode_nil(const char *buf, int *index, union my_obj* dummy)
return ret ? ret : !(type == ERL_NIL_EXT);
}
-int my_encode_nil(char *buf, int *index, union my_obj* dummy)
+int my_encode_nil(char *buf, int *index, struct my_obj* dummy)
{
return ei_encode_empty_list(buf, index);
}
-int my_x_encode_nil(ei_x_buff* x, union my_obj* dummy)
+int my_x_encode_nil(ei_x_buff* x, struct my_obj* dummy)
{
return ei_x_encode_empty_list(x);
}
struct Type nil_type = {
- "empty_list", "nil", (decodeFT*)my_decode_nil,
+ "empty_list", "nil", my_decode_nil,
my_encode_nil, my_x_encode_nil
};
-int my_encode_map_header(char *buf, int *index, union my_obj* obj)
+int my_decode_map_header(const char *buf, int *index, struct my_obj* obj)
{
- return ei_encode_map_header(buf, index, obj->arity);
+ int ret = ei_decode_map_header(buf, index, &obj->u.arity);
+ if (ret == 0 && obj)
+ obj->nterms = obj->u.arity * 2;
+ return ret;
}
-int my_x_encode_map_header(ei_x_buff* x, union my_obj* obj)
+int my_encode_map_header(char *buf, int *index, struct my_obj* obj)
{
- return ei_x_encode_map_header(x, (long)obj->arity);
+ return ei_encode_map_header(buf, index, obj->u.arity);
+}
+int my_x_encode_map_header(ei_x_buff* x, struct my_obj* obj)
+{
+ return ei_x_encode_map_header(x, (long)obj->u.arity);
}
struct Type map_type = {
- "map_header", "arity", (decodeFT*)ei_decode_map_header,
+ "map_header", "arity", my_decode_map_header,
my_encode_map_header, my_x_encode_map_header
};
@@ -185,7 +214,8 @@ struct Type map_type = {
void decode_encode(struct Type** tv, int nobj)
{
- union my_obj obj;
+ struct my_obj objv[10];
+ int oix = 0;
char* packet;
char* inp;
char* outp;
@@ -224,7 +254,9 @@ void decode_encode(struct Type** tv, int nobj)
}
size2 = 0;
- err = t->ei_decode_fp(inp, &size2, &obj);
+ objv[oix].nterms = 0;
+ objv[oix].startp = inp;
+ err = t->ei_decode_fp(inp, &size2, &objv[oix]);
if (err != 0) {
if (err != -1) {
fail("decode returned non zero but not -1");
@@ -239,7 +271,7 @@ void decode_encode(struct Type** tv, int nobj)
return;
}
- if (t != &tuple_type && t != &list_type && t != &map_type) {
+ if (!objv[oix].nterms) {
size2 = 0;
err = ei_skip_term(inp, &size2);
if (err != 0) {
@@ -255,7 +287,7 @@ void decode_encode(struct Type** tv, int nobj)
MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type);
size2 = 0;
- err = t->ei_encode_fp(NULL, &size2, &obj);
+ err = t->ei_encode_fp(NULL, &size2, &objv[oix]);
if (err != 0) {
if (err != -1) {
fail("size calculation returned non zero but not -1");
@@ -272,7 +304,7 @@ void decode_encode(struct Type** tv, int nobj)
}
MESSAGE("ei_encode_%s, arg is type %s", t->name, t->type);
size3 = 0;
- err = t->ei_encode_fp(outp, &size3, &obj);
+ err = t->ei_encode_fp(outp, &size3, &objv[oix]);
if (err != 0) {
if (err != -1) {
fail("returned non zero but not -1");
@@ -288,7 +320,7 @@ void decode_encode(struct Type** tv, int nobj)
}
MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type);
- err = t->ei_x_encode_fp(&arg, &obj);
+ err = t->ei_x_encode_fp(&arg, &objv[oix]);
if (err != 0) {
if (err != -1) {
fail("returned non zero but not -1");
@@ -306,6 +338,37 @@ void decode_encode(struct Type** tv, int nobj)
inp += size1;
outp += size1;
+
+ if (objv[oix].nterms) { /* container term */
+ if (++oix >= sizeof(objv)/sizeof(*objv))
+ fail("Term too deep");
+ }
+ else { /* "leaf" term */
+ while (oix > 0) {
+ if (--(objv[oix - 1].nterms) == 0) {
+ /* last element in container */
+ --oix;
+
+ size2 = 0;
+ err = ei_skip_term(objv[oix].startp, &size2);
+ if (err != 0) {
+ fail("ei_skip_term returned non zero");
+ return;
+ }
+ if (objv[oix].startp + size2 != inp) {
+ MESSAGE("size1 = %d, size2 = %d\n", size1, size2);
+ fail("container skip size differs");
+ return;
+ }
+ }
+ else
+ break; /* more elements in container */
+ }
+ }
+
+ }
+ if (oix > 0) {
+ fail("Container not complete");
}
send_buffer(out_buf, outp - out_buf);
send_buffer(arg.buff, arg.index);
--
cgit v1.2.3
From c543d5bff7fb23c3f44cc4817c0654117de78919 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Wed, 12 Mar 2014 20:11:10 +0100
Subject: erts: Change external format for maps
to be: 116,Arity, K1,V1,K2,V2,...,Kn,Vn
instead of: 116,Arity, K1,K2,...,Kn, V1,V2,....,Vn
We think this will be better for future internal map structures
like HAMT. Would be bad if we need to iterate twice over HAMT
in term_to_binary, one for keys and one for values.
---
lib/debugger/test/map_SUITE.erl | 9 +++++----
lib/erl_interface/doc/src/ei.xml | 18 ++++++++----------
.../ei_decode_encode_test.c | 5 +++--
.../java_src/com/ericsson/otp/erlang/OtpErlangMap.java | 4 ----
lib/jinterface/test/jinterface_SUITE_data/Maps.java | 8 ++++----
5 files changed, 20 insertions(+), 24 deletions(-)
(limited to 'lib')
diff --git a/lib/debugger/test/map_SUITE.erl b/lib/debugger/test/map_SUITE.erl
index e9f4ea1fad..741ad2dc41 100644
--- a/lib/debugger/test/map_SUITE.erl
+++ b/lib/debugger/test/map_SUITE.erl
@@ -790,16 +790,16 @@ t_map_encode_decode(Config) when is_list(Config) ->
%% literally #{ b=>2, a=>1 } in the internal order
#{ a:=1, b:=2 } =
- erlang:binary_to_term(<<131,116,0,0,0,2,100,0,1,98,100,0,1,97,97,2,97,1>>),
+ erlang:binary_to_term(<<131,116,0,0,0,2,100,0,1,98,97,2,100,0,1,97,97,1>>),
%% literally #{ "hi" => "value", a=>33, b=>55 } in the internal order
#{ a:=33, b:=55, "hi" := "value"} = erlang:binary_to_term(<<131,116,0,0,0,3,
107,0,2,104,105, % "hi" :: list()
- 100,0,1,97, % a :: atom()
- 100,0,1,98, % b :: atom()
107,0,5,118,97,108,117,101, % "value" :: list()
+ 100,0,1,97, % a :: atom()
97,33, % 33 :: integer()
+ 100,0,1,98, % b :: atom()
97,55 % 55 :: integer()
>>),
@@ -829,7 +829,8 @@ map_encode_decode_and_match([{K,V}|Pairs], EncodedPairs, M0) ->
B0 = erlang:term_to_binary(M1),
Ls = lists:sort(fun(A,B) -> erts_internal:cmp_term(A,B) < 0 end, [{K, erlang:term_to_binary(K), erlang:term_to_binary(V)}|EncodedPairs]),
%% sort Ks and Vs according to term spec, then match it
- ok = match_encoded_map(B0, length(Ls), [Kbin||{_,Kbin,_}<-Ls] ++ [Vbin||{_,_,Vbin}<-Ls]),
+ KVbins = lists:foldr(fun({_,Kbin,Vbin}, Acc) -> [Kbin,Vbin | Acc] end, [], Ls),
+ ok = match_encoded_map(B0, length(Ls), KVbins),
%% decode and match it
M1 = erlang:binary_to_term(B0),
map_encode_decode_and_match(Pairs,Ls,M1);
diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml
index 1756ee8a7d..90495eebd6 100644
--- a/lib/erl_interface/doc/src/ei.xml
+++ b/lib/erl_interface/doc/src/ei.xml
@@ -422,19 +422,18 @@ ei_x_encode_empty_list(&x);
Encode a map
This function encodes a map header, with a specified arity. The next
- arity terms encoded will be the keys of the map, and the next
- arity terms after that will be the corresponding values in
- same order.
+ arity*2 terms encoded will be the keys and values of the map
+ encoded in the following order: K1, V1, K2, V2, ..., Kn, Vn.
+
E.g. to encode the map #{a => "Apple", b => "Banana"}:
ei_x_encode_map_header(&x, 2);
ei_x_encode_atom(&x, "a");
-ei_x_encode_atom(&x, "b");
ei_x_encode_string(&x, "Apple");
+ei_x_encode_atom(&x, "b");
ei_x_encode_string(&x, "Banana");
- A correctly encoded map can not have duplicate keys, but no check
- for duplicate keys is done by this function.
+ A correctly encoded map can not have duplicate keys.
@@ -664,10 +663,9 @@ ei_x_encode_string(&x, "Banana");
This function decodes a map header from the binary
format. The number of key-value pairs is returned in
- arity. Keys and values follows, first all keys and then all values,
- which makes a total of arity*2 terms.
- Keys and values are paired according to their order, the first key
- with the first value and so on. If arity is zero, it's an empty map.
+ *arity. Keys and values follow in the following order:
+ K1, V1, K2, V2, ..., Kn, Vn. This makes a total of
+ arity*2 terms. If arity is zero, it's an empty map.
A correctly encoded map does not have duplicate keys.
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 790d498a1d..fcf546105b 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -527,8 +527,9 @@ TESTCASE(test_ei_decode_encode)
{ /* #{atom => atom, atom => pid, port => ref }*/
struct Type* map[] = { &map_type,
- &my_atom_type, &my_atom_type, &port_type,
- &my_atom_type, &pid_type, &ref_type
+ &my_atom_type, &my_atom_type,
+ &my_atom_type, &pid_type,
+ &port_type, &ref_type
};
decode_encode(map, 7);
}
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java
index 7c1cf84e98..03c18e55a2 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java
@@ -125,8 +125,6 @@ public class OtpErlangMap extends OtpErlangObject implements Serializable,
for (int i = 0; i < arity; i++) {
keys[i] = buf.read_any();
- }
- for (int i = 0; i < arity; i++) {
values[i] = buf.read_any();
}
} else {
@@ -227,8 +225,6 @@ public class OtpErlangMap extends OtpErlangObject implements Serializable,
for (int i = 0; i < arity; i++) {
buf.write_any(keys[i]);
- }
- for (int i = 0; i < arity; i++) {
buf.write_any(values[i]);
}
}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/Maps.java b/lib/jinterface/test/jinterface_SUITE_data/Maps.java
index 136a665f23..653defc621 100644
--- a/lib/jinterface/test/jinterface_SUITE_data/Maps.java
+++ b/lib/jinterface/test/jinterface_SUITE_data/Maps.java
@@ -42,16 +42,16 @@ class Maps {
runTest(new byte[] { (byte) 131, 116, 0, 0, 0, 1, 100, 0, 1, 97, 100,
0, 1, 98 }, "#{a => b}", 2);
// make sure keys are sorted here, jinterface doesn't reorder them
- runTest(new byte[] { (byte) 131, 116, 0, 0, 0, 2, 97, 2, 100, 0, 1, 97,
- 106, 97, 1 }, "#{2 => [],a => 1}", 3);
+ runTest(new byte[] { (byte) 131, 116, 0, 0, 0, 2, 97, 2, 106,
+ 100, 0, 1, 97, 97, 1 }, "#{2 => [],a => 1}", 3);
runTest(new byte[] { (byte) 131, 116, 0, 0, 0, 1, 104, 1, 97, 3, 108,
0, 0, 0, 1, 100, 0, 1, 114, 106 }, "#{{3} => [r]}", 4);
try {
// #{2 => [],a => 1}
final OtpErlangMap map = new OtpErlangMap(new OtpInputStream(
- new byte[] { (byte) 131, 116, 0, 0, 0, 2, 97, 2, 100, 0, 1,
- 97, 106, 97, 1 }));
+ new byte[] { (byte) 131, 116, 0, 0, 0, 2, 97, 2, 106,
+ 100, 0, 1, 97, 97, 1 }));
if (map.arity() != 2) {
fail(5);
--
cgit v1.2.3
From a996e168bfebe599cfe393cd132a87984d905d84 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Thu, 13 Mar 2014 15:23:44 +0100
Subject: erts: Add distribution capability flag for maps DFLAG_MAP_TAG
This is just a preparation to allow detection of older nodes
that do not understand maps (R16 and older).
---
lib/erl_interface/src/connect/ei_connect.c | 5 +++--
lib/erl_interface/src/connect/ei_connect_int.h | 3 ++-
lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java | 5 +++--
lib/kernel/include/dist.hrl | 3 ++-
lib/kernel/src/dist_util.erl | 5 +++--
5 files changed, 13 insertions(+), 8 deletions(-)
(limited to 'lib')
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index c9aa28812c..3175d1bdfd 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -1336,7 +1336,8 @@ static int send_name_or_challenge(int fd, char *nodename,
| DFLAG_NEW_FUN_TAGS
| DFLAG_NEW_FLOATS
| DFLAG_SMALL_ATOM_TAGS
- | DFLAG_UTF8_ATOMS));
+ | DFLAG_UTF8_ATOMS
+ | DFLAG_MAP_TAG));
if (f_chall)
put32be(s, challenge);
memcpy(s, nodename, strlen(nodename));
diff --git a/lib/erl_interface/src/connect/ei_connect_int.h b/lib/erl_interface/src/connect/ei_connect_int.h
index 42ab9b58d7..8fab47a787 100644
--- a/lib/erl_interface/src/connect/ei_connect_int.h
+++ b/lib/erl_interface/src/connect/ei_connect_int.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -104,6 +104,7 @@ extern int h_errno;
#define DFLAG_NEW_FLOATS 0x800
#define DFLAG_SMALL_ATOM_TAGS 0x4000
#define DFLAG_UTF8_ATOMS 0x10000
+#define DFLAG_MAP_TAG 0x20000
ei_cnode *ei_fd_to_cnode(int fd);
int ei_distversion(int fd);
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
index 968f284bff..3ef44b8851 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -92,6 +92,7 @@ public class AbstractNode {
static final int dFlagNewFloats = 0x800;
static final int dFlagUnicodeIo = 0x1000;
static final int dFlagUtf8Atoms = 0x10000;
+ static final int dFlagMapTag = 0x20000;
int ntype = NTYPE_R6;
int proto = 0; // tcp/ip
@@ -100,7 +101,7 @@ public class AbstractNode {
int creation = 0;
int flags = dFlagExtendedReferences | dFlagExtendedPidsPorts
| dFlagBitBinaries | dFlagNewFloats | dFlagFunTags
- | dflagNewFunTags | dFlagUtf8Atoms;
+ | dflagNewFunTags | dFlagUtf8Atoms | dFlagMapTag;
/* initialize hostname and default cookie */
static {
diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl
index e32c112e63..77556d1303 100644
--- a/lib/kernel/include/dist.hrl
+++ b/lib/kernel/include/dist.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,3 +37,4 @@
-define(DFLAG_DIST_HDR_ATOM_CACHE,16#2000).
-define(DFLAG_SMALL_ATOM_TAGS, 16#4000).
-define(DFLAG_UTF8_ATOMS, 16#10000).
+-define(DFLAG_MAP_TAG, 16#20000).
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index fc50ec6717..b127fe2e33 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -116,7 +116,8 @@ make_this_flags(RequestType, OtherNode) ->
?DFLAG_UNICODE_IO bor
?DFLAG_DIST_HDR_ATOM_CACHE bor
?DFLAG_SMALL_ATOM_TAGS bor
- ?DFLAG_UTF8_ATOMS).
+ ?DFLAG_UTF8_ATOMS bor
+ ?DFLAG_MAP_TAG).
handshake_other_started(#hs_data{request_type=ReqType}=HSData0) ->
{PreOtherFlags,Node,Version} = recv_name(HSData0),
--
cgit v1.2.3