Implement container operators API function (#4697)
Basically re-opening and updating #4275 Co-authored-by: bence gabor kis <kisbg@inf.u-szeged.hu> JerryScript-DCO-1.0-Signed-off-by: Bela Toth tbela@inf.u-szeged.hu Co-authored-by: bence gabor kis <kisbg@inf.u-szeged.hu>
This commit is contained in:
@@ -478,6 +478,18 @@ typedef struct jerry_context_t jerry_context_t;
|
||||
|
||||
*New in version 2.0*.
|
||||
|
||||
## jerry_container_operation_t
|
||||
|
||||
Enum that contains the supported container operation types
|
||||
- JERRY_CONTAINER_OP_ADD - Set/WeakSet add operation
|
||||
- JERRY_CONTAINER_OP_GET - Map/WeakMap get operation
|
||||
- JERRY_CONTAINER_OP_SET - Map/WeakMap set operation
|
||||
- JERRY_CONTAINER_OP_HAS - Set/WeakSet/Map/WeakMap has operation
|
||||
- JERRY_CONTAINER_OP_DELETE - Set/WeakSet/Map/WeakMap delete operation
|
||||
- JERRY_CONTAINER_OP_SIZE - Set/WeakSet/Map/WeakMap size operation
|
||||
- JERRY_CONTAINER_OP_CLEAR - Set/Map clear operation
|
||||
|
||||
*New in version [[NEXT_RELEASE]]*.
|
||||
|
||||
## jerry_binary_operation_t
|
||||
|
||||
@@ -12429,3 +12441,78 @@ main (void)
|
||||
|
||||
- [jerry_create_container](#jerry_create_container)
|
||||
- [jerry_container_type_t](#jerry_container_type_t)
|
||||
|
||||
|
||||
## jerry_container_operation
|
||||
|
||||
**Summary**
|
||||
|
||||
Perform container operation on the given operands (add, delete, set, etc.).
|
||||
|
||||
*Note*:
|
||||
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
|
||||
is no longer needed.
|
||||
- This API function depends on a build option (`JERRY_BUILTIN_CONTAINER`) and can be checked
|
||||
runtime with the `JERRY_FEATURE_MAP` , `JERRY_FEATURE_SET` , `JERRY_FEATURE_WEAKMAP` , `JERRY_FEATURE_WEAKSET`
|
||||
feature enum values.
|
||||
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
|
||||
- The es.next profile enables this by default.
|
||||
|
||||
**Prototype**
|
||||
|
||||
```c
|
||||
jerry_value_t
|
||||
jerry_container_operation (jerry_container_operation_t operation,
|
||||
jerry_value_t container,
|
||||
jerry_value_t *arguments,
|
||||
uint32_t arguments_number)
|
||||
```
|
||||
|
||||
- `operation` - container operation
|
||||
- `container` - this value
|
||||
- `arguments` - array of arguments
|
||||
- `arguments_number` - number of arguments
|
||||
- result if the operation is successful
|
||||
- error, otherwise
|
||||
|
||||
*New in version [[NEXT_RELEASE]]*.
|
||||
|
||||
**Example**
|
||||
|
||||
[doctest]: # ()
|
||||
|
||||
```c
|
||||
#include "jerryscript.h"
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
jerry_value_t map = jerry_create_container (JERRY_CONTAINER_TYPE_MAP, NULL, 0);
|
||||
jerry_value_t key_str = jerry_create_string ((jerry_char_t *) "number");
|
||||
jerry_value_t number = jerry_create_number (10);
|
||||
jerry_value_t args[2] = {key_str, number};
|
||||
|
||||
jerry_value_t result = jerry_container_operation (JERRY_CONTAINER_OP_SET, map, args, 2);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, map, NULL, 0);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_CLEAR, map, NULL, 0);
|
||||
jerry_release_value (result);
|
||||
|
||||
jerry_release_value (map);
|
||||
jerry_release_value (key_str);
|
||||
jerry_release_value (number);
|
||||
|
||||
jerry_cleanup ();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_create_container](#jerry_create_container)
|
||||
- [jerry_container_type_t](#jerry_container_type_t)
|
||||
|
||||
@@ -6708,6 +6708,154 @@ jerry_get_array_from_container (jerry_value_t value, /**< the container or itera
|
||||
#endif
|
||||
} /* jerry_get_array_from_container */
|
||||
|
||||
/**
|
||||
* Perform container operation on the given operands (add, get, set, has, delete, size, clear).
|
||||
*
|
||||
* @return error - if argument is invalid or operation is unsuccessful or unsupported
|
||||
* result of the container operation - otherwise.
|
||||
*/
|
||||
jerry_value_t
|
||||
jerry_container_operation (jerry_container_operation_t operation, /**< container operation */
|
||||
jerry_value_t container, /**< container */
|
||||
jerry_value_t *arguments, /**< list of arguments */
|
||||
uint32_t arguments_number) /**< number of arguments */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
#if JERRY_BUILTIN_CONTAINER
|
||||
if (!ecma_is_value_object (container))
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Container is not an object.")));
|
||||
}
|
||||
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (container);
|
||||
|
||||
if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_CLASS)
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Container is not a container object.")));
|
||||
}
|
||||
uint16_t type = ((ecma_extended_object_t *) obj_p)->u.cls.u2.container_id;
|
||||
ecma_extended_object_t *container_object_p = ecma_op_container_get_object (container, type);
|
||||
|
||||
if (container_object_p == NULL)
|
||||
{
|
||||
return ecma_create_error_reference_from_context ();
|
||||
}
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case JERRY_CONTAINER_OP_ADD:
|
||||
case JERRY_CONTAINER_OP_DELETE:
|
||||
case JERRY_CONTAINER_OP_GET:
|
||||
case JERRY_CONTAINER_OP_HAS:
|
||||
{
|
||||
if (arguments_number != 1 || ecma_is_value_error_reference (arguments[0]))
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_SET:
|
||||
{
|
||||
if (arguments_number != 2
|
||||
|| ecma_is_value_error_reference (arguments[0])
|
||||
|| ecma_is_value_error_reference (arguments[1]))
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_CLEAR:
|
||||
case JERRY_CONTAINER_OP_SIZE:
|
||||
{
|
||||
if (arguments_number != 0)
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_wrong_args_msg_p)));
|
||||
}
|
||||
}
|
||||
|
||||
jerry_value_t result;
|
||||
const char *incorrect_type_call = ECMA_ERR_MSG ("Operator called on incorrect container type");
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case JERRY_CONTAINER_OP_ADD:
|
||||
{
|
||||
if (type == LIT_MAGIC_STRING_MAP_UL || type == LIT_MAGIC_STRING_WEAKMAP_UL)
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (incorrect_type_call));
|
||||
}
|
||||
result = ecma_op_container_set (container_object_p, arguments[0], arguments[0], type);
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_GET:
|
||||
{
|
||||
if (type == LIT_MAGIC_STRING_SET_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (incorrect_type_call));
|
||||
}
|
||||
result = ecma_op_container_get (container_object_p, arguments[0], type);
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_SET:
|
||||
{
|
||||
if (type == LIT_MAGIC_STRING_SET_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (incorrect_type_call));
|
||||
}
|
||||
result = ecma_op_container_set (container_object_p, arguments[0], arguments[1], type);
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_HAS:
|
||||
{
|
||||
result = ecma_op_container_has (container_object_p, arguments[0], type);
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_DELETE:
|
||||
{
|
||||
if (type == LIT_MAGIC_STRING_WEAKMAP_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
|
||||
{
|
||||
result = ecma_op_container_delete_weak (container_object_p, arguments[0], type);
|
||||
break;
|
||||
}
|
||||
result = ecma_op_container_delete (container_object_p, arguments[0], type);
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_SIZE:
|
||||
{
|
||||
result = ecma_op_container_size (container_object_p);
|
||||
break;
|
||||
}
|
||||
case JERRY_CONTAINER_OP_CLEAR:
|
||||
{
|
||||
if (type == LIT_MAGIC_STRING_WEAKSET_UL || type == LIT_MAGIC_STRING_WEAKMAP_UL)
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (incorrect_type_call));
|
||||
}
|
||||
result = ecma_op_container_clear (container_object_p);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
result = jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Unsupported container operation")));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return jerry_return (result);
|
||||
#else /* JERRY_BUILTIN_CONTAINER */
|
||||
JERRY_UNUSED (operation);
|
||||
JERRY_UNUSED (container);
|
||||
JERRY_UNUSED (arguments);
|
||||
JERRY_UNUSED (arguments_number);
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_container_not_supported_p)));
|
||||
#endif /* JERRY_BUILTIN_CONTAINER */
|
||||
} /* jerry_container_operation */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -434,6 +434,10 @@ jerry_value_t jerry_create_container (jerry_container_type_t container_type,
|
||||
jerry_length_t arguments_list_len);
|
||||
jerry_container_type_t jerry_get_container_type (const jerry_value_t value);
|
||||
jerry_value_t jerry_get_array_from_container (jerry_value_t value, bool *is_key_value_p);
|
||||
jerry_value_t jerry_container_operation (jerry_container_operation_t operation,
|
||||
jerry_value_t container,
|
||||
jerry_value_t *arguments,
|
||||
uint32_t arguments_number);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -749,6 +749,20 @@ typedef enum
|
||||
JERRY_CONTAINER_TYPE_WEAKSET, /**< WeakSet type */
|
||||
} jerry_container_type_t;
|
||||
|
||||
/**
|
||||
* Container operations
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JERRY_CONTAINER_OP_ADD, /**< Set/WeakSet add operation */
|
||||
JERRY_CONTAINER_OP_GET, /**< Map/WeakMap get operation */
|
||||
JERRY_CONTAINER_OP_SET, /**< Map/WeakMap set operation */
|
||||
JERRY_CONTAINER_OP_HAS, /**< Set/WeakSet/Map/WeakMap has operation */
|
||||
JERRY_CONTAINER_OP_DELETE, /**< Set/WeakSet/Map/WeakMap delete operation */
|
||||
JERRY_CONTAINER_OP_SIZE, /**< Set/WeakSet/Map/WeakMap size operation */
|
||||
JERRY_CONTAINER_OP_CLEAR, /**< Set/Map clear operation */
|
||||
} jerry_container_operation_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@ set(SOURCE_UNIT_TEST_MAIN_MODULES
|
||||
test-backtrace.c
|
||||
test-bigint.c
|
||||
test-container.c
|
||||
test-container-operation.c
|
||||
test-context-data.c
|
||||
test-dataview.c
|
||||
test-date-helpers.c
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "jerryscript.h"
|
||||
#include "test-common.h"
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
if (!jerry_is_feature_enabled (JERRY_FEATURE_MAP)
|
||||
|| !jerry_is_feature_enabled (JERRY_FEATURE_SET)
|
||||
|| !jerry_is_feature_enabled (JERRY_FEATURE_WEAKMAP)
|
||||
|| !jerry_is_feature_enabled (JERRY_FEATURE_WEAKSET))
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Containers are disabled!\n");
|
||||
jerry_cleanup ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Map container tests
|
||||
jerry_value_t map = jerry_create_container (JERRY_CONTAINER_TYPE_MAP, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_container_type (map) == JERRY_CONTAINER_TYPE_MAP);
|
||||
|
||||
jerry_value_t key_str = jerry_create_string ((jerry_char_t *) "number");
|
||||
jerry_value_t number = jerry_create_number (10);
|
||||
jerry_value_t args[2] = {key_str, number};
|
||||
jerry_value_t result = jerry_container_operation (JERRY_CONTAINER_OP_SET, map, args, 2);
|
||||
TEST_ASSERT (!jerry_value_is_error (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_GET, map, &key_str, 1);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 10);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_HAS, map, &key_str, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, map, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 1);
|
||||
jerry_release_value (result);
|
||||
|
||||
key_str = jerry_create_string ((jerry_char_t *) "number2");
|
||||
number = jerry_create_number (11);
|
||||
jerry_value_t args2[2] = {key_str, number};
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SET, map, args2, 2);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, map, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 2);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_DELETE, map, &key_str, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, map, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 1);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_CLEAR, map, NULL, 0);
|
||||
TEST_ASSERT (jerry_value_is_undefined (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, map, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 0);
|
||||
jerry_release_value (result);
|
||||
|
||||
// Set container tests
|
||||
number = jerry_create_number (10);
|
||||
jerry_value_t set = jerry_create_container (JERRY_CONTAINER_TYPE_SET, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_container_type (set) == JERRY_CONTAINER_TYPE_SET);
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_ADD, set, &number, 1);
|
||||
TEST_ASSERT (!jerry_value_is_error (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_HAS, set, &number, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, set, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 1);
|
||||
jerry_release_value (result);
|
||||
|
||||
number = jerry_create_number (11);
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_ADD, set, &number, 1);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, set, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 2);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_DELETE, set, &number, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, set, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 1);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_CLEAR, set, NULL, 0);
|
||||
TEST_ASSERT (jerry_value_is_undefined (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SIZE, set, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_number_value (result) == 0);
|
||||
jerry_release_value (result);
|
||||
jerry_release_value (set);
|
||||
|
||||
// WeakMap contanier tests
|
||||
number = jerry_create_number (10);
|
||||
jerry_value_t weak_map = jerry_create_container (JERRY_CONTAINER_TYPE_WEAKMAP, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_container_type (weak_map) == JERRY_CONTAINER_TYPE_WEAKMAP);
|
||||
|
||||
jerry_value_t obj = jerry_create_object ();
|
||||
number = jerry_create_number (10);
|
||||
jerry_value_t args4[2] = {obj, number};
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SET, weak_map, args4, 2);
|
||||
TEST_ASSERT (!jerry_value_is_error (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_HAS, weak_map, &obj, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_DELETE, weak_map, &obj, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
jerry_release_value (weak_map);
|
||||
|
||||
// WeakSet contanier tests,
|
||||
jerry_value_t weak_set = jerry_create_container (JERRY_CONTAINER_TYPE_WEAKSET, NULL, 0);
|
||||
TEST_ASSERT (jerry_get_container_type (weak_set) == JERRY_CONTAINER_TYPE_WEAKSET);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_ADD, weak_set, &obj, 1);
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_HAS, weak_set, &obj, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_DELETE, weak_set, &obj, 1);
|
||||
TEST_ASSERT (jerry_value_is_true (result));
|
||||
jerry_release_value (result);
|
||||
jerry_release_value (weak_set);
|
||||
|
||||
// container is not a object
|
||||
jerry_value_t empty_val = jerry_create_undefined ();
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SET, empty_val, args, 2);
|
||||
TEST_ASSERT (jerry_value_is_error (result));
|
||||
jerry_release_value (result);
|
||||
|
||||
// arguments is a error
|
||||
const char * const error_message_p = "Random error.";
|
||||
jerry_value_t error_val = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
|
||||
jerry_value_t args3[2] = { error_val, error_val };
|
||||
result = jerry_container_operation (JERRY_CONTAINER_OP_SET, map, args3, 2);
|
||||
TEST_ASSERT (jerry_value_is_error (result));
|
||||
jerry_release_value (result);
|
||||
jerry_release_value (error_val);
|
||||
jerry_release_value (map);
|
||||
|
||||
jerry_release_value (key_str);
|
||||
jerry_release_value (number);
|
||||
jerry_release_value (obj);
|
||||
jerry_cleanup ();
|
||||
return 0;
|
||||
|
||||
} /* main */
|
||||
Reference in New Issue
Block a user