summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authoryzshen <yzshen@chromium.org>2016-03-15 11:43:53 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-15 18:46:37 +0000
commit583ed9487b207982774fcfa11c563b7add77a808 (patch)
tree643ec1bf9e4bb6800bb5bf629640280e097f168a /mojo
parent37b82939f4a1dca844292eb73874bfd8175c7754 (diff)
downloadchromium_src-583ed9487b207982774fcfa11c563b7add77a808.zip
chromium_src-583ed9487b207982774fcfa11c563b7add77a808.tar.gz
chromium_src-583ed9487b207982774fcfa11c563b7add77a808.tar.bz2
Mojo C++ bindings: introduce mojo::WTFArray.
mojo::WTFArray is a thin wrapper around WTF::Vector. It is move-only and can express null array. You can move WTF::Vector in/out of mojo::WTFArray. If "--for_blink" is specified for the bindings generator, the generator will map mojo array to mojo::WTFArray BUG=583738 Review URL: https://codereview.chromium.org/1766093002 Cr-Commit-Position: refs/heads/master@{#381265}
Diffstat (limited to 'mojo')
-rw-r--r--mojo/mojo_edk_tests.gyp9
-rw-r--r--mojo/mojo_public.gyp2
-rw-r--r--mojo/public/cpp/bindings/BUILD.gn2
-rw-r--r--mojo/public/cpp/bindings/array.h3
-rw-r--r--mojo/public/cpp/bindings/lib/array_serialization_traits.h3
-rw-r--r--mojo/public/cpp/bindings/lib/connector.cc4
-rw-r--r--mojo/public/cpp/bindings/lib/serialization_forward.h23
-rw-r--r--mojo/public/cpp/bindings/lib/value_traits.h4
-rw-r--r--mojo/public/cpp/bindings/lib/wtf_array_serialization.h43
-rw-r--r--mojo/public/cpp/bindings/lib/wtf_serialization.h1
-rw-r--r--mojo/public/cpp/bindings/tests/BUILD.gn9
-rw-r--r--mojo/public/cpp/bindings/tests/array_common_test.h392
-rw-r--r--mojo/public/cpp/bindings/tests/array_unittest.cc393
-rw-r--r--mojo/public/cpp/bindings/tests/wtf_array_unittest.cc62
-rw-r--r--mojo/public/cpp/bindings/tests/wtf_types_unittest.cc75
-rw-r--r--mojo/public/cpp/bindings/wtf_array.h235
-rw-r--r--mojo/public/interfaces/bindings/tests/BUILD.gn4
-rw-r--r--mojo/public/interfaces/bindings/tests/test_wtf_types.mojom6
-rw-r--r--mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl3
-rw-r--r--mojo/public/tools/bindings/generators/mojom_cpp_generator.py12
20 files changed, 872 insertions, 413 deletions
diff --git a/mojo/mojo_edk_tests.gyp b/mojo/mojo_edk_tests.gyp
index 539a161..01d01c4 100644
--- a/mojo/mojo_edk_tests.gyp
+++ b/mojo/mojo_edk_tests.gyp
@@ -57,6 +57,7 @@
'mojo_public.gyp:mojo_public_test_utils',
],
'sources': [
+ 'public/cpp/bindings/tests/array_common_test.h',
'public/cpp/bindings/tests/array_unittest.cc',
'public/cpp/bindings/tests/associated_interface_unittest.cc',
'public/cpp/bindings/tests/binding_callback_unittest.cc',
@@ -67,6 +68,7 @@
'public/cpp/bindings/tests/connector_unittest.cc',
'public/cpp/bindings/tests/constant_unittest.cc',
'public/cpp/bindings/tests/container_test_util.cc',
+ 'public/cpp/bindings/tests/container_test_util.h',
'public/cpp/bindings/tests/equals_unittest.cc',
'public/cpp/bindings/tests/handle_passing_unittest.cc',
'public/cpp/bindings/tests/interface_ptr_unittest.cc',
@@ -98,6 +100,7 @@
'public/cpp/bindings/tests/type_conversion_unittest.cc',
'public/cpp/bindings/tests/union_unittest.cc',
'public/cpp/bindings/tests/validation_unittest.cc',
+ 'public/cpp/bindings/tests/variant_test_util.h',
],
},
{
@@ -107,10 +110,16 @@
'dependencies': [
'../testing/gtest.gyp:gtest',
'mojo_public.gyp:mojo_cpp_bindings',
+ 'mojo_public.gyp:mojo_public_test_interfaces',
'mojo_public.gyp:mojo_public_test_wtf_types',
'mojo_public.gyp:mojo_public_test_wtf_types_blink',
],
'sources': [
+ 'public/cpp/bindings/tests/array_common_test.h',
+ 'public/cpp/bindings/tests/container_test_util.cc',
+ 'public/cpp/bindings/tests/container_test_util.h',
+ 'public/cpp/bindings/tests/variant_test_util.h',
+ 'public/cpp/bindings/tests/wtf_array_unittest.cc',
'public/cpp/bindings/tests/wtf_types_unittest.cc',
],
},
diff --git a/mojo/mojo_public.gyp b/mojo/mojo_public.gyp
index da318ae..bb12a5b 100644
--- a/mojo/mojo_public.gyp
+++ b/mojo/mojo_public.gyp
@@ -204,9 +204,11 @@
'..'
],
'sources': [
+ 'public/cpp/bindings/lib/wtf_array_serialization.h',
'public/cpp/bindings/lib/wtf_serialization.h',
'public/cpp/bindings/lib/wtf_string_serialization.cc',
'public/cpp/bindings/lib/wtf_string_serialization.h',
+ 'public/cpp/bindings/wtf_array.h',
],
'dependencies': [
'mojo_cpp_bindings',
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 1939ff6..b817de7 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -127,9 +127,11 @@ source_set("callback") {
source_set("wtf_support") {
sources = [
+ "lib/wtf_array_serialization.h",
"lib/wtf_serialization.h",
"lib/wtf_string_serialization.cc",
"lib/wtf_string_serialization.h",
+ "wtf_array.h",
]
public_deps = [
diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h
index 575ba77..f522faa 100644
--- a/mojo/public/cpp/bindings/array.h
+++ b/mojo/public/cpp/bindings/array.h
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "base/move.h"
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/template_util.h"
@@ -221,7 +222,7 @@ class Array {
struct CloneTraits<U, true> {
static inline void Clone(const std::vector<T>& src_vec,
std::vector<T>* dest_vec) {
- dest_vec->clear();
+ DCHECK(dest_vec->empty());
dest_vec->reserve(src_vec.size());
for (const auto& element : src_vec)
dest_vec->push_back(element.Clone());
diff --git a/mojo/public/cpp/bindings/lib/array_serialization_traits.h b/mojo/public/cpp/bindings/lib/array_serialization_traits.h
index 35b12f1..5e0e5af 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization_traits.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization_traits.h
@@ -194,7 +194,8 @@ struct ArraySerializer<
private:
template <typename T,
- bool is_array = IsSpecializationOf<Array, T>::value,
+ bool is_array = IsSpecializationOf<Array, T>::value ||
+ IsSpecializationOf<WTFArray, T>::value,
bool is_string = std::is_same<T, String>::value ||
std::is_same<T, WTF::String>::value>
struct SerializeCaller {
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index 065c176..55263a9 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -287,8 +287,8 @@ void Connector::WaitToReadMore() {
// If the watch failed because the handle is invalid or its conditions can
// no longer be met, we signal the error asynchronously to avoid reentry.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&Connector::OnWatcherHandleReady,
- weak_self_, rv));
+ FROM_HERE,
+ base::Bind(&Connector::OnWatcherHandleReady, weak_self_, rv));
}
if (register_sync_handle_watch_count_ > 0 &&
diff --git a/mojo/public/cpp/bindings/lib/serialization_forward.h b/mojo/public/cpp/bindings/lib/serialization_forward.h
index 39d046c..b605049 100644
--- a/mojo/public/cpp/bindings/lib/serialization_forward.h
+++ b/mojo/public/cpp/bindings/lib/serialization_forward.h
@@ -23,6 +23,9 @@ class Array;
template <typename K, typename V>
class Map;
+template <typename T>
+class WTFArray;
+
namespace internal {
template <typename T>
@@ -80,6 +83,26 @@ inline bool Deserialize_(internal::Array_Data<F>* input,
internal::SerializationContext* context);
// -----------------------------------------------------------------------------
+// Forward declaration for WTFArray.
+
+template <typename E>
+inline size_t GetSerializedSize_(const WTFArray<E>& input,
+ internal::SerializationContext* context);
+
+template <typename E, typename F>
+inline void SerializeArray_(
+ WTFArray<E> input,
+ internal::Buffer* buf,
+ internal::Array_Data<F>** output,
+ const internal::ArrayValidateParams* validate_params,
+ internal::SerializationContext* context);
+
+template <typename E, typename F>
+inline bool Deserialize_(internal::Array_Data<F>* input,
+ WTFArray<E>* output,
+ internal::SerializationContext* context);
+
+// -----------------------------------------------------------------------------
// Forward declaration for Map.
template <typename MapKey, typename MapValue>
diff --git a/mojo/public/cpp/bindings/lib/value_traits.h b/mojo/public/cpp/bindings/lib/value_traits.h
index d3b295b..56bdf3a 100644
--- a/mojo/public/cpp/bindings/lib/value_traits.h
+++ b/mojo/public/cpp/bindings/lib/value_traits.h
@@ -36,6 +36,9 @@ class ScopedHandleBase;
template <typename T>
class StructPtr;
+template <typename T>
+class WTFArray;
+
namespace internal {
template <typename T, typename Enable = void>
@@ -47,6 +50,7 @@ template <typename T>
struct ValueTraits<
T,
typename EnableIf<IsSpecializationOf<Array, T>::value ||
+ IsSpecializationOf<WTFArray, T>::value ||
IsSpecializationOf<Map, T>::value ||
IsSpecializationOf<StructPtr, T>::value ||
IsSpecializationOf<InlinedStructPtr, T>::value>::type> {
diff --git a/mojo/public/cpp/bindings/lib/wtf_array_serialization.h b/mojo/public/cpp/bindings/lib/wtf_array_serialization.h
new file mode 100644
index 0000000..70edbf1
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/wtf_array_serialization.h
@@ -0,0 +1,43 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_ARRAY_SERIALIZATION_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_ARRAY_SERIALIZATION_H_
+
+#include <stddef.h>
+
+#include "mojo/public/cpp/bindings/lib/array_serialization_traits.h"
+#include "mojo/public/cpp/bindings/wtf_array.h"
+
+namespace mojo {
+
+template <typename E>
+inline size_t GetSerializedSize_(const WTFArray<E>& input,
+ internal::SerializationContext* context) {
+ return internal::ArraySerializationImpl<WTFArray<E>>::GetSerializedSize(
+ input, context);
+}
+
+template <typename E, typename F>
+inline void SerializeArray_(
+ WTFArray<E> input,
+ internal::Buffer* buf,
+ internal::Array_Data<F>** output,
+ const internal::ArrayValidateParams* validate_params,
+ internal::SerializationContext* context) {
+ return internal::ArraySerializationImpl<WTFArray<E>>::template Serialize<F>(
+ std::move(input), buf, output, validate_params, context);
+}
+
+template <typename E, typename F>
+inline bool Deserialize_(internal::Array_Data<F>* input,
+ WTFArray<E>* output,
+ internal::SerializationContext* context) {
+ return internal::ArraySerializationImpl<WTFArray<E>>::template Deserialize<F>(
+ input, output, context);
+}
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_ARRAY_SERIALIZATION_H_
diff --git a/mojo/public/cpp/bindings/lib/wtf_serialization.h b/mojo/public/cpp/bindings/lib/wtf_serialization.h
index 11733ec..318d152 100644
--- a/mojo/public/cpp/bindings/lib/wtf_serialization.h
+++ b/mojo/public/cpp/bindings/lib/wtf_serialization.h
@@ -5,6 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
+#include "mojo/public/cpp/bindings/lib/wtf_array_serialization.h"
#include "mojo/public/cpp/bindings/lib/wtf_string_serialization.h"
#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_WTF_SERIALIZATION_H_
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn
index 7bbd0bd..043ed74 100644
--- a/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -8,6 +8,7 @@ source_set("tests") {
testonly = true
sources = [
+ "array_common_test.h",
"array_unittest.cc",
"associated_interface_unittest.cc",
"binding_callback_unittest.cc",
@@ -18,6 +19,7 @@ source_set("tests") {
"connector_unittest.cc",
"constant_unittest.cc",
"container_test_util.cc",
+ "container_test_util.h",
"equals_unittest.cc",
"handle_passing_unittest.cc",
"interface_ptr_unittest.cc",
@@ -49,6 +51,7 @@ source_set("tests") {
"type_conversion_unittest.cc",
"union_unittest.cc",
"validation_unittest.cc",
+ "variant_test_util.h",
]
deps = [
@@ -72,6 +75,11 @@ source_set("for_blink_tests") {
testonly = true
sources = [
+ "array_common_test.h",
+ "container_test_util.cc",
+ "container_test_util.h",
+ "variant_test_util.h",
+ "wtf_array_unittest.cc",
"wtf_types_unittest.cc",
]
@@ -79,6 +87,7 @@ source_set("for_blink_tests") {
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/bindings:callback",
"//mojo/public/cpp/system",
+ "//mojo/public/interfaces/bindings/tests:test_interfaces",
"//mojo/public/interfaces/bindings/tests:test_wtf_types",
"//mojo/public/interfaces/bindings/tests:test_wtf_types_blink",
"//testing/gtest",
diff --git a/mojo/public/cpp/bindings/tests/array_common_test.h b/mojo/public/cpp/bindings/tests/array_common_test.h
new file mode 100644
index 0000000..19c0f6f
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/array_common_test.h
@@ -0,0 +1,392 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <utility>
+
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/tests/container_test_util.h"
+#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+
+// Common tests for both mojo::Array and mojo::WTFArray.
+template <template <typename...> class ArrayType>
+class ArrayCommonTest {
+ public:
+ // Tests null and empty arrays.
+ static void NullAndEmpty() {
+ ArrayType<char> array0;
+ EXPECT_TRUE(array0.empty());
+ EXPECT_FALSE(array0.is_null());
+ array0 = nullptr;
+ EXPECT_TRUE(array0.is_null());
+ EXPECT_FALSE(array0.empty());
+
+ ArrayType<char> array1(nullptr);
+ EXPECT_TRUE(array1.is_null());
+ EXPECT_FALSE(array1.empty());
+ array1.SetToEmpty();
+ EXPECT_TRUE(array1.empty());
+ EXPECT_FALSE(array1.is_null());
+ }
+
+ // Tests that basic array operations work.
+ static void Basic() {
+ ArrayType<char> array(8);
+ for (size_t i = 0; i < array.size(); ++i) {
+ char val = static_cast<char>(i * 2);
+ array[i] = val;
+ EXPECT_EQ(val, array.at(i));
+ }
+ }
+
+ // Tests that basic ArrayType<bool> operations work.
+ static void Bool() {
+ ArrayType<bool> array(64);
+ for (size_t i = 0; i < array.size(); ++i) {
+ bool val = i % 3 == 0;
+ array[i] = val;
+ EXPECT_EQ(val, array.at(i));
+ }
+ }
+
+ // Tests that ArrayType<ScopedMessagePipeHandle> supports transferring
+ // handles.
+ static void Handle() {
+ MessagePipe pipe;
+ ArrayType<ScopedMessagePipeHandle> handles(2);
+ handles[0] = std::move(pipe.handle0);
+ handles[1].reset(pipe.handle1.release());
+
+ EXPECT_FALSE(pipe.handle0.is_valid());
+ EXPECT_FALSE(pipe.handle1.is_valid());
+
+ ArrayType<ScopedMessagePipeHandle> handles2 = std::move(handles);
+ EXPECT_TRUE(handles2[0].is_valid());
+ EXPECT_TRUE(handles2[1].is_valid());
+
+ ScopedMessagePipeHandle pipe_handle = std::move(handles2[0]);
+ EXPECT_TRUE(pipe_handle.is_valid());
+ EXPECT_FALSE(handles2[0].is_valid());
+ }
+
+ // Tests that ArrayType<ScopedMessagePipeHandle> supports closing handles.
+ static void HandlesAreClosed() {
+ MessagePipe pipe;
+ MojoHandle pipe0_value = pipe.handle0.get().value();
+ MojoHandle pipe1_value = pipe.handle0.get().value();
+
+ {
+ ArrayType<ScopedMessagePipeHandle> handles(2);
+ handles[0] = std::move(pipe.handle0);
+ handles[1].reset(pipe.handle0.release());
+ }
+
+ // We expect the pipes to have been closed.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value));
+ }
+
+ static void Clone() {
+ {
+ // Test POD.
+ ArrayType<int32_t> array(3);
+ for (size_t i = 0; i < array.size(); ++i)
+ array[i] = static_cast<int32_t>(i);
+
+ ArrayType<int32_t> clone_array = array.Clone();
+ EXPECT_EQ(array.size(), clone_array.size());
+ for (size_t i = 0; i < array.size(); ++i)
+ EXPECT_EQ(array[i], clone_array[i]);
+ }
+
+ {
+ // Test copyable object.
+ ArrayType<String> array(2);
+ array[0] = "hello";
+ array[1] = "world";
+
+ ArrayType<String> clone_array = array.Clone();
+ EXPECT_EQ(array.size(), clone_array.size());
+ for (size_t i = 0; i < array.size(); ++i)
+ EXPECT_EQ(array[i], clone_array[i]);
+ }
+
+ {
+ // Test struct.
+ ArrayType<RectPtr> array(2);
+ array[1] = Rect::New();
+ array[1]->x = 1;
+ array[1]->y = 2;
+ array[1]->width = 3;
+ array[1]->height = 4;
+
+ ArrayType<RectPtr> clone_array = array.Clone();
+ EXPECT_EQ(array.size(), clone_array.size());
+ EXPECT_TRUE(clone_array[0].is_null());
+ EXPECT_EQ(array[1]->x, clone_array[1]->x);
+ EXPECT_EQ(array[1]->y, clone_array[1]->y);
+ EXPECT_EQ(array[1]->width, clone_array[1]->width);
+ EXPECT_EQ(array[1]->height, clone_array[1]->height);
+ }
+
+ {
+ // Test array of array.
+ ArrayType<ArrayType<int8_t>> array(2);
+ array[0] = nullptr;
+ array[1] = ArrayType<int8_t>(2);
+ array[1][0] = 0;
+ array[1][1] = 1;
+
+ ArrayType<ArrayType<int8_t>> clone_array = array.Clone();
+ EXPECT_EQ(array.size(), clone_array.size());
+ EXPECT_TRUE(clone_array[0].is_null());
+ EXPECT_EQ(array[1].size(), clone_array[1].size());
+ EXPECT_EQ(array[1][0], clone_array[1][0]);
+ EXPECT_EQ(array[1][1], clone_array[1][1]);
+ }
+
+ {
+ // Test that array of handles still works although Clone() is not
+ // available.
+ ArrayType<ScopedMessagePipeHandle> array(10);
+ EXPECT_FALSE(array[0].is_valid());
+ }
+ }
+
+ static void Serialization_ArrayOfPOD() {
+ ArrayType<int32_t> array(4);
+ for (size_t i = 0; i < array.size(); ++i)
+ array[i] = static_cast<int32_t>(i);
+
+ size_t size = GetSerializedSize_(array, nullptr);
+ EXPECT_EQ(8U + 4 * 4U, size);
+
+ mojo::internal::FixedBufferForTesting buf(size);
+ mojo::internal::Array_Data<int32_t>* data;
+ mojo::internal::ArrayValidateParams validate_params(0, false, nullptr);
+ SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
+
+ ArrayType<int32_t> array2;
+ Deserialize_(data, &array2, nullptr);
+
+ EXPECT_EQ(4U, array2.size());
+ for (size_t i = 0; i < array2.size(); ++i)
+ EXPECT_EQ(static_cast<int32_t>(i), array2[i]);
+ }
+
+ static void Serialization_EmptyArrayOfPOD() {
+ ArrayType<int32_t> array;
+ size_t size = GetSerializedSize_(array, nullptr);
+ EXPECT_EQ(8U, size);
+
+ mojo::internal::FixedBufferForTesting buf(size);
+ mojo::internal::Array_Data<int32_t>* data;
+ mojo::internal::ArrayValidateParams validate_params(0, false, nullptr);
+ SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
+
+ ArrayType<int32_t> array2;
+ Deserialize_(data, &array2, nullptr);
+ EXPECT_EQ(0U, array2.size());
+ }
+
+ static void Serialization_ArrayOfArrayOfPOD() {
+ ArrayType<ArrayType<int32_t>> array(2);
+ for (size_t j = 0; j < array.size(); ++j) {
+ ArrayType<int32_t> inner(4);
+ for (size_t i = 0; i < inner.size(); ++i)
+ inner[i] = static_cast<int32_t>(i + (j * 10));
+ array[j] = std::move(inner);
+ }
+
+ size_t size = GetSerializedSize_(array, nullptr);
+ EXPECT_EQ(8U + 2 * 8U + 2 * (8U + 4 * 4U), size);
+
+ mojo::internal::FixedBufferForTesting buf(size);
+ mojo::internal::Array_Data<mojo::internal::Array_Data<int32_t>*>* data;
+ mojo::internal::ArrayValidateParams validate_params(
+ 0, false, new mojo::internal::ArrayValidateParams(0, false, nullptr));
+ SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
+
+ ArrayType<ArrayType<int32_t>> array2;
+ Deserialize_(data, &array2, nullptr);
+
+ EXPECT_EQ(2U, array2.size());
+ for (size_t j = 0; j < array2.size(); ++j) {
+ const ArrayType<int32_t>& inner = array2[j];
+ EXPECT_EQ(4U, inner.size());
+ for (size_t i = 0; i < inner.size(); ++i)
+ EXPECT_EQ(static_cast<int32_t>(i + (j * 10)), inner[i]);
+ }
+ }
+
+ static void Serialization_ArrayOfBool() {
+ ArrayType<bool> array(10);
+ for (size_t i = 0; i < array.size(); ++i)
+ array[i] = i % 2 ? true : false;
+
+ size_t size = GetSerializedSize_(array, nullptr);
+ EXPECT_EQ(8U + 8U, size);
+
+ mojo::internal::FixedBufferForTesting buf(size);
+ mojo::internal::Array_Data<bool>* data;
+ mojo::internal::ArrayValidateParams validate_params(0, false, nullptr);
+ SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
+
+ ArrayType<bool> array2;
+ Deserialize_(data, &array2, nullptr);
+
+ EXPECT_EQ(10U, array2.size());
+ for (size_t i = 0; i < array2.size(); ++i)
+ EXPECT_EQ(i % 2 ? true : false, array2[i]);
+ }
+
+ static void Serialization_ArrayOfString() {
+ ArrayType<String> array(10);
+ for (size_t i = 0; i < array.size(); ++i) {
+ char c = 'A' + static_cast<char>(i);
+ array[i] = String(&c, 1);
+ }
+
+ size_t size = GetSerializedSize_(array, nullptr);
+ EXPECT_EQ(8U + // array header
+ 10 * 8U + // array payload (10 pointers)
+ 10 * (8U + // string header
+ 8U), // string length of 1 padded to 8
+ size);
+
+ mojo::internal::FixedBufferForTesting buf(size);
+ mojo::internal::Array_Data<mojo::internal::String_Data*>* data;
+ mojo::internal::ArrayValidateParams validate_params(
+ 0, false, new mojo::internal::ArrayValidateParams(0, false, nullptr));
+ SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
+
+ ArrayType<String> array2;
+ Deserialize_(data, &array2, nullptr);
+
+ EXPECT_EQ(10U, array2.size());
+ for (size_t i = 0; i < array2.size(); ++i) {
+ char c = 'A' + static_cast<char>(i);
+ EXPECT_EQ(String(&c, 1), array2[i]);
+ }
+ }
+
+ static void Resize_Copyable() {
+ ASSERT_EQ(0u, CopyableType::num_instances());
+ ArrayType<CopyableType> array(3);
+ std::vector<CopyableType*> value_ptrs;
+ value_ptrs.push_back(array[0].ptr());
+ value_ptrs.push_back(array[1].ptr());
+
+ for (size_t i = 0; i < array.size(); i++)
+ array[i].ResetCopied();
+
+ array.resize(2);
+ ASSERT_EQ(2u, array.size());
+ EXPECT_EQ(array.size(), CopyableType::num_instances());
+ for (size_t i = 0; i < array.size(); i++) {
+ EXPECT_FALSE(array[i].copied());
+ EXPECT_EQ(value_ptrs[i], array[i].ptr());
+ }
+
+ array.resize(3);
+ array[2].ResetCopied();
+ ASSERT_EQ(3u, array.size());
+ EXPECT_EQ(array.size(), CopyableType::num_instances());
+ for (size_t i = 0; i < array.size(); i++)
+ EXPECT_FALSE(array[i].copied());
+ value_ptrs.push_back(array[2].ptr());
+
+ size_t capacity = array.storage().capacity();
+ array.resize(capacity);
+ ASSERT_EQ(capacity, array.size());
+ EXPECT_EQ(array.size(), CopyableType::num_instances());
+ for (size_t i = 0; i < 3; i++)
+ EXPECT_FALSE(array[i].copied());
+ for (size_t i = 3; i < array.size(); i++) {
+ array[i].ResetCopied();
+ value_ptrs.push_back(array[i].ptr());
+ }
+
+ array.resize(capacity + 2);
+ ASSERT_EQ(capacity + 2, array.size());
+ EXPECT_EQ(array.size(), CopyableType::num_instances());
+ for (size_t i = 0; i < capacity; i++) {
+ EXPECT_TRUE(array[i].copied());
+ EXPECT_EQ(value_ptrs[i], array[i].ptr());
+ }
+ array = nullptr;
+ EXPECT_EQ(0u, CopyableType::num_instances());
+ EXPECT_FALSE(array);
+ array.resize(0);
+ EXPECT_EQ(0u, CopyableType::num_instances());
+ EXPECT_TRUE(array);
+ }
+
+ static void Resize_MoveOnly() {
+ ASSERT_EQ(0u, MoveOnlyType::num_instances());
+ ArrayType<MoveOnlyType> array(3);
+ std::vector<MoveOnlyType*> value_ptrs;
+ value_ptrs.push_back(array[0].ptr());
+ value_ptrs.push_back(array[1].ptr());
+
+ for (size_t i = 0; i < array.size(); i++)
+ EXPECT_FALSE(array[i].moved());
+
+ array.resize(2);
+ ASSERT_EQ(2u, array.size());
+ EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+ for (size_t i = 0; i < array.size(); i++) {
+ EXPECT_FALSE(array[i].moved());
+ EXPECT_EQ(value_ptrs[i], array[i].ptr());
+ }
+
+ array.resize(3);
+ ASSERT_EQ(3u, array.size());
+ EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+ for (size_t i = 0; i < array.size(); i++)
+ EXPECT_FALSE(array[i].moved());
+ value_ptrs.push_back(array[2].ptr());
+
+ size_t capacity = array.storage().capacity();
+ array.resize(capacity);
+ ASSERT_EQ(capacity, array.size());
+ EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+ for (size_t i = 0; i < array.size(); i++)
+ EXPECT_FALSE(array[i].moved());
+ for (size_t i = 3; i < array.size(); i++)
+ value_ptrs.push_back(array[i].ptr());
+
+ array.resize(capacity + 2);
+ ASSERT_EQ(capacity + 2, array.size());
+ EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
+ for (size_t i = 0; i < capacity; i++) {
+ EXPECT_TRUE(array[i].moved());
+ EXPECT_EQ(value_ptrs[i], array[i].ptr());
+ }
+ for (size_t i = capacity; i < array.size(); i++)
+ EXPECT_FALSE(array[i].moved());
+
+ array = nullptr;
+ EXPECT_EQ(0u, MoveOnlyType::num_instances());
+ EXPECT_FALSE(array);
+ array.resize(0);
+ EXPECT_EQ(0u, MoveOnlyType::num_instances());
+ EXPECT_TRUE(array);
+ }
+};
+
+#define ARRAY_COMMON_TEST(ArrayType, test_name) \
+ TEST_F(ArrayType##Test, test_name) { \
+ ArrayCommonTest<ArrayType>::test_name(); \
+ }
+
+} // namespace test
+} // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc
index f4dad7c..0700bb1 100644
--- a/mojo/public/cpp/bindings/tests/array_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/array_unittest.cc
@@ -4,391 +4,34 @@
#include "mojo/public/cpp/bindings/array.h"
-#include <stddef.h>
-#include <stdint.h>
-#include <utility>
-
-#include "mojo/public/cpp/bindings/lib/array_internal.h"
-#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/tests/array_common_test.h"
#include "mojo/public/cpp/bindings/tests/container_test_util.h"
-#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace test {
namespace {
-using mojo::internal::Array_Data;
-using mojo::internal::ArrayValidateParams;
-using mojo::internal::FixedBufferForTesting;
-using mojo::internal::String_Data;
-
using ArrayTest = testing::Test;
-// Tests null and empty arrays.
-TEST_F(ArrayTest, NullAndEmpty) {
- Array<char> array0;
- EXPECT_TRUE(array0.empty());
- EXPECT_FALSE(array0.is_null());
- array0 = nullptr;
- EXPECT_TRUE(array0.is_null());
- EXPECT_FALSE(array0.empty());
-
- Array<char> array1(nullptr);
- EXPECT_TRUE(array1.is_null());
- EXPECT_FALSE(array1.empty());
- array1.SetToEmpty();
- EXPECT_TRUE(array1.empty());
- EXPECT_FALSE(array1.is_null());
-}
-
-// Tests that basic Array operations work.
-TEST_F(ArrayTest, Basic) {
- Array<char> array(8);
- for (size_t i = 0; i < array.size(); ++i) {
- char val = static_cast<char>(i * 2);
- array[i] = val;
- EXPECT_EQ(val, array.at(i));
- }
-}
-
-// Tests that basic Array<bool> operations work.
-TEST_F(ArrayTest, Bool) {
- Array<bool> array(64);
- for (size_t i = 0; i < array.size(); ++i) {
- bool val = i % 3 == 0;
- array[i] = val;
- EXPECT_EQ(val, array.at(i));
- }
-}
-
-// Tests that Array<ScopedMessagePipeHandle> supports transferring handles.
-TEST_F(ArrayTest, Handle) {
- MessagePipe pipe;
- Array<ScopedMessagePipeHandle> handles(2);
- handles[0] = std::move(pipe.handle0);
- handles[1].reset(pipe.handle1.release());
-
- EXPECT_FALSE(pipe.handle0.is_valid());
- EXPECT_FALSE(pipe.handle1.is_valid());
-
- Array<ScopedMessagePipeHandle> handles2 = std::move(handles);
- EXPECT_TRUE(handles2[0].is_valid());
- EXPECT_TRUE(handles2[1].is_valid());
-
- ScopedMessagePipeHandle pipe_handle = std::move(handles2[0]);
- EXPECT_TRUE(pipe_handle.is_valid());
- EXPECT_FALSE(handles2[0].is_valid());
-}
-
-// Tests that Array<ScopedMessagePipeHandle> supports closing handles.
-TEST_F(ArrayTest, HandlesAreClosed) {
- MessagePipe pipe;
- MojoHandle pipe0_value = pipe.handle0.get().value();
- MojoHandle pipe1_value = pipe.handle0.get().value();
-
- {
- Array<ScopedMessagePipeHandle> handles(2);
- handles[0] = std::move(pipe.handle0);
- handles[1].reset(pipe.handle0.release());
- }
-
- // We expect the pipes to have been closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value));
-}
-
-TEST_F(ArrayTest, Clone) {
- {
- // Test POD.
- Array<int32_t> array(3);
- for (size_t i = 0; i < array.size(); ++i)
- array[i] = static_cast<int32_t>(i);
-
- Array<int32_t> clone_array = array.Clone();
- EXPECT_EQ(array.size(), clone_array.size());
- for (size_t i = 0; i < array.size(); ++i)
- EXPECT_EQ(array[i], clone_array[i]);
- }
-
- {
- // Test copyable object.
- Array<String> array(2);
- array[0] = "hello";
- array[1] = "world";
-
- Array<String> clone_array = array.Clone();
- EXPECT_EQ(array.size(), clone_array.size());
- for (size_t i = 0; i < array.size(); ++i)
- EXPECT_EQ(array[i], clone_array[i]);
- }
-
- {
- // Test struct.
- Array<RectPtr> array(2);
- array[1] = Rect::New();
- array[1]->x = 1;
- array[1]->y = 2;
- array[1]->width = 3;
- array[1]->height = 4;
-
- Array<RectPtr> clone_array = array.Clone();
- EXPECT_EQ(array.size(), clone_array.size());
- EXPECT_TRUE(clone_array[0].is_null());
- EXPECT_EQ(array[1]->x, clone_array[1]->x);
- EXPECT_EQ(array[1]->y, clone_array[1]->y);
- EXPECT_EQ(array[1]->width, clone_array[1]->width);
- EXPECT_EQ(array[1]->height, clone_array[1]->height);
- }
-
- {
- // Test array of array.
- Array<Array<int8_t>> array(2);
- array[0] = nullptr;
- array[1] = Array<int8_t>(2);
- array[1][0] = 0;
- array[1][1] = 1;
-
- Array<Array<int8_t>> clone_array = array.Clone();
- EXPECT_EQ(array.size(), clone_array.size());
- EXPECT_TRUE(clone_array[0].is_null());
- EXPECT_EQ(array[1].size(), clone_array[1].size());
- EXPECT_EQ(array[1][0], clone_array[1][0]);
- EXPECT_EQ(array[1][1], clone_array[1][1]);
- }
-
- {
- // Test that array of handles still works although Clone() is not available.
- Array<ScopedMessagePipeHandle> array(10);
- EXPECT_FALSE(array[0].is_valid());
- }
-}
-
-TEST_F(ArrayTest, Serialization_ArrayOfPOD) {
- Array<int32_t> array(4);
- for (size_t i = 0; i < array.size(); ++i)
- array[i] = static_cast<int32_t>(i);
-
- size_t size = GetSerializedSize_(array, nullptr);
- EXPECT_EQ(8U + 4 * 4U, size);
-
- FixedBufferForTesting buf(size);
- Array_Data<int32_t>* data;
- ArrayValidateParams validate_params(0, false, nullptr);
- SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
-
- Array<int32_t> array2;
- Deserialize_(data, &array2, nullptr);
-
- EXPECT_EQ(4U, array2.size());
- for (size_t i = 0; i < array2.size(); ++i)
- EXPECT_EQ(static_cast<int32_t>(i), array2[i]);
-}
-
-TEST_F(ArrayTest, Serialization_EmptyArrayOfPOD) {
- Array<int32_t> array;
- size_t size = GetSerializedSize_(array, nullptr);
- EXPECT_EQ(8U, size);
-
- FixedBufferForTesting buf(size);
- Array_Data<int32_t>* data;
- ArrayValidateParams validate_params(0, false, nullptr);
- SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
-
- Array<int32_t> array2;
- Deserialize_(data, &array2, nullptr);
- EXPECT_EQ(0U, array2.size());
-}
-
-TEST_F(ArrayTest, Serialization_ArrayOfArrayOfPOD) {
- Array<Array<int32_t>> array(2);
- for (size_t j = 0; j < array.size(); ++j) {
- Array<int32_t> inner(4);
- for (size_t i = 0; i < inner.size(); ++i)
- inner[i] = static_cast<int32_t>(i + (j * 10));
- array[j] = std::move(inner);
- }
-
- size_t size = GetSerializedSize_(array, nullptr);
- EXPECT_EQ(8U + 2 * 8U + 2 * (8U + 4 * 4U), size);
-
- FixedBufferForTesting buf(size);
- Array_Data<Array_Data<int32_t>*>* data;
- ArrayValidateParams validate_params(
- 0, false, new ArrayValidateParams(0, false, nullptr));
- SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
-
- Array<Array<int32_t>> array2;
- Deserialize_(data, &array2, nullptr);
-
- EXPECT_EQ(2U, array2.size());
- for (size_t j = 0; j < array2.size(); ++j) {
- const Array<int32_t>& inner = array2[j];
- EXPECT_EQ(4U, inner.size());
- for (size_t i = 0; i < inner.size(); ++i)
- EXPECT_EQ(static_cast<int32_t>(i + (j * 10)), inner[i]);
- }
-}
-
-TEST_F(ArrayTest, Serialization_ArrayOfBool) {
- Array<bool> array(10);
- for (size_t i = 0; i < array.size(); ++i)
- array[i] = i % 2 ? true : false;
-
- size_t size = GetSerializedSize_(array, nullptr);
- EXPECT_EQ(8U + 8U, size);
-
- FixedBufferForTesting buf(size);
- Array_Data<bool>* data;
- ArrayValidateParams validate_params(0, false, nullptr);
- SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
-
- Array<bool> array2;
- Deserialize_(data, &array2, nullptr);
-
- EXPECT_EQ(10U, array2.size());
- for (size_t i = 0; i < array2.size(); ++i)
- EXPECT_EQ(i % 2 ? true : false, array2[i]);
-}
-
-TEST_F(ArrayTest, Serialization_ArrayOfString) {
- Array<String> array(10);
- for (size_t i = 0; i < array.size(); ++i) {
- char c = 'A' + static_cast<char>(i);
- array[i] = String(&c, 1);
- }
-
- size_t size = GetSerializedSize_(array, nullptr);
- EXPECT_EQ(8U + // array header
- 10 * 8U + // array payload (10 pointers)
- 10 * (8U + // string header
- 8U), // string length of 1 padded to 8
- size);
-
- FixedBufferForTesting buf(size);
- Array_Data<String_Data*>* data;
- ArrayValidateParams validate_params(
- 0, false, new ArrayValidateParams(0, false, nullptr));
- SerializeArray_(std::move(array), &buf, &data, &validate_params, nullptr);
-
- Array<String> array2;
- Deserialize_(data, &array2, nullptr);
-
- EXPECT_EQ(10U, array2.size());
- for (size_t i = 0; i < array2.size(); ++i) {
- char c = 'A' + static_cast<char>(i);
- EXPECT_EQ(String(&c, 1), array2[i]);
- }
-}
-
-TEST_F(ArrayTest, Resize_Copyable) {
- ASSERT_EQ(0u, CopyableType::num_instances());
- mojo::Array<CopyableType> array(3);
- std::vector<CopyableType*> value_ptrs;
- value_ptrs.push_back(array[0].ptr());
- value_ptrs.push_back(array[1].ptr());
-
- for (size_t i = 0; i < array.size(); i++)
- array[i].ResetCopied();
-
- array.resize(2);
- ASSERT_EQ(2u, array.size());
- EXPECT_EQ(array.size(), CopyableType::num_instances());
- for (size_t i = 0; i < array.size(); i++) {
- EXPECT_FALSE(array[i].copied());
- EXPECT_EQ(value_ptrs[i], array[i].ptr());
- }
-
- array.resize(3);
- array[2].ResetCopied();
- ASSERT_EQ(3u, array.size());
- EXPECT_EQ(array.size(), CopyableType::num_instances());
- for (size_t i = 0; i < array.size(); i++)
- EXPECT_FALSE(array[i].copied());
- value_ptrs.push_back(array[2].ptr());
-
- size_t capacity = array.storage().capacity();
- array.resize(capacity);
- ASSERT_EQ(capacity, array.size());
- EXPECT_EQ(array.size(), CopyableType::num_instances());
- for (size_t i = 0; i < 3; i++)
- EXPECT_FALSE(array[i].copied());
- for (size_t i = 3; i < array.size(); i++) {
- array[i].ResetCopied();
- value_ptrs.push_back(array[i].ptr());
- }
-
- array.resize(capacity + 2);
- ASSERT_EQ(capacity + 2, array.size());
- EXPECT_EQ(array.size(), CopyableType::num_instances());
- for (size_t i = 0; i < capacity; i++) {
- EXPECT_TRUE(array[i].copied());
- EXPECT_EQ(value_ptrs[i], array[i].ptr());
- }
- array = nullptr;
- EXPECT_EQ(0u, CopyableType::num_instances());
- EXPECT_FALSE(array);
- array.resize(0);
- EXPECT_EQ(0u, CopyableType::num_instances());
- EXPECT_TRUE(array);
-}
-
-TEST_F(ArrayTest, Resize_MoveOnly) {
- ASSERT_EQ(0u, MoveOnlyType::num_instances());
- mojo::Array<MoveOnlyType> array(3);
- std::vector<MoveOnlyType*> value_ptrs;
- value_ptrs.push_back(array[0].ptr());
- value_ptrs.push_back(array[1].ptr());
-
- for (size_t i = 0; i < array.size(); i++)
- EXPECT_FALSE(array[i].moved());
-
- array.resize(2);
- ASSERT_EQ(2u, array.size());
- EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
- for (size_t i = 0; i < array.size(); i++) {
- EXPECT_FALSE(array[i].moved());
- EXPECT_EQ(value_ptrs[i], array[i].ptr());
- }
-
- array.resize(3);
- ASSERT_EQ(3u, array.size());
- EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
- for (size_t i = 0; i < array.size(); i++)
- EXPECT_FALSE(array[i].moved());
- value_ptrs.push_back(array[2].ptr());
-
- size_t capacity = array.storage().capacity();
- array.resize(capacity);
- ASSERT_EQ(capacity, array.size());
- EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
- for (size_t i = 0; i < array.size(); i++)
- EXPECT_FALSE(array[i].moved());
- for (size_t i = 3; i < array.size(); i++)
- value_ptrs.push_back(array[i].ptr());
-
- array.resize(capacity + 2);
- ASSERT_EQ(capacity + 2, array.size());
- EXPECT_EQ(array.size(), MoveOnlyType::num_instances());
- for (size_t i = 0; i < capacity; i++) {
- EXPECT_TRUE(array[i].moved());
- EXPECT_EQ(value_ptrs[i], array[i].ptr());
- }
- for (size_t i = capacity; i < array.size(); i++)
- EXPECT_FALSE(array[i].moved());
-
- array = nullptr;
- EXPECT_EQ(0u, MoveOnlyType::num_instances());
- EXPECT_FALSE(array);
- array.resize(0);
- EXPECT_EQ(0u, MoveOnlyType::num_instances());
- EXPECT_TRUE(array);
-}
+ARRAY_COMMON_TEST(Array, NullAndEmpty)
+ARRAY_COMMON_TEST(Array, Basic)
+ARRAY_COMMON_TEST(Array, Bool)
+ARRAY_COMMON_TEST(Array, Handle)
+ARRAY_COMMON_TEST(Array, HandlesAreClosed)
+ARRAY_COMMON_TEST(Array, Clone)
+ARRAY_COMMON_TEST(Array, Serialization_ArrayOfPOD)
+ARRAY_COMMON_TEST(Array, Serialization_EmptyArrayOfPOD)
+ARRAY_COMMON_TEST(Array, Serialization_ArrayOfArrayOfPOD)
+ARRAY_COMMON_TEST(Array, Serialization_ArrayOfBool)
+ARRAY_COMMON_TEST(Array, Serialization_ArrayOfString)
+ARRAY_COMMON_TEST(Array, Resize_Copyable)
+ARRAY_COMMON_TEST(Array, Resize_MoveOnly)
TEST_F(ArrayTest, PushBack_Copyable) {
ASSERT_EQ(0u, CopyableType::num_instances());
- mojo::Array<CopyableType> array(2);
+ Array<CopyableType> array(2);
array = nullptr;
std::vector<CopyableType*> value_ptrs;
size_t capacity = array.storage().capacity();
@@ -423,7 +66,7 @@ TEST_F(ArrayTest, PushBack_Copyable) {
TEST_F(ArrayTest, PushBack_MoveOnly) {
ASSERT_EQ(0u, MoveOnlyType::num_instances());
- mojo::Array<MoveOnlyType> array(2);
+ Array<MoveOnlyType> array(2);
array = nullptr;
std::vector<MoveOnlyType*> value_ptrs;
size_t capacity = array.storage().capacity();
@@ -458,7 +101,7 @@ TEST_F(ArrayTest, PushBack_MoveOnly) {
TEST_F(ArrayTest, MoveFromAndToSTLVector_Copyable) {
std::vector<CopyableType> vec1(1);
- mojo::Array<CopyableType> arr(std::move(vec1));
+ Array<CopyableType> arr(std::move(vec1));
ASSERT_EQ(1u, arr.size());
ASSERT_FALSE(arr[0].copied());
@@ -472,7 +115,7 @@ TEST_F(ArrayTest, MoveFromAndToSTLVector_Copyable) {
TEST_F(ArrayTest, MoveFromAndToSTLVector_MoveOnly) {
std::vector<MoveOnlyType> vec1(1);
- mojo::Array<MoveOnlyType> arr(std::move(vec1));
+ Array<MoveOnlyType> arr(std::move(vec1));
ASSERT_EQ(1u, arr.size());
diff --git a/mojo/public/cpp/bindings/tests/wtf_array_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_array_unittest.cc
new file mode 100644
index 0000000..bb54b9c
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/wtf_array_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/cpp/bindings/wtf_array.h"
+
+#include "mojo/public/cpp/bindings/lib/serialization.h"
+#include "mojo/public/cpp/bindings/lib/wtf_serialization.h"
+#include "mojo/public/cpp/bindings/tests/array_common_test.h"
+#include "mojo/public/cpp/bindings/tests/container_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+using WTFArrayTest = testing::Test;
+
+ARRAY_COMMON_TEST(WTFArray, NullAndEmpty)
+ARRAY_COMMON_TEST(WTFArray, Basic)
+ARRAY_COMMON_TEST(WTFArray, Bool)
+ARRAY_COMMON_TEST(WTFArray, Handle)
+ARRAY_COMMON_TEST(WTFArray, HandlesAreClosed)
+ARRAY_COMMON_TEST(WTFArray, Clone)
+ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfPOD)
+ARRAY_COMMON_TEST(WTFArray, Serialization_EmptyArrayOfPOD)
+ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfArrayOfPOD)
+ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfBool)
+ARRAY_COMMON_TEST(WTFArray, Serialization_ArrayOfString)
+ARRAY_COMMON_TEST(WTFArray, Resize_Copyable)
+ARRAY_COMMON_TEST(WTFArray, Resize_MoveOnly)
+
+TEST_F(WTFArrayTest, MoveFromAndToWTFVector_Copyable) {
+ WTF::Vector<CopyableType> vec1(1);
+ WTFArray<CopyableType> arr(std::move(vec1));
+ ASSERT_EQ(1u, arr.size());
+ ASSERT_FALSE(arr[0].copied());
+
+ WTF::Vector<CopyableType> vec2(arr.PassStorage());
+ ASSERT_EQ(1u, vec2.size());
+ ASSERT_FALSE(vec2[0].copied());
+
+ ASSERT_EQ(0u, arr.size());
+ ASSERT_TRUE(arr.is_null());
+}
+
+TEST_F(WTFArrayTest, MoveFromAndToWTFVector_MoveOnly) {
+ WTF::Vector<MoveOnlyType> vec1(1);
+ WTFArray<MoveOnlyType> arr(std::move(vec1));
+
+ ASSERT_EQ(1u, arr.size());
+
+ WTF::Vector<MoveOnlyType> vec2(arr.PassStorage());
+ ASSERT_EQ(1u, vec2.size());
+
+ ASSERT_EQ(0u, arr.size());
+ ASSERT_TRUE(arr.is_null());
+}
+
+} // namespace
+} // namespace test
+} // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
index 20486eb..ef781bc 100644
--- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -34,6 +34,11 @@ class TestWTFImpl : public TestWTF {
callback.Run(str);
}
+ void EchoStringArray(Array<String> arr,
+ const EchoStringArrayCallback& callback) override {
+ callback.Run(std::move(arr));
+ }
+
private:
Binding<TestWTF> binding_;
};
@@ -46,17 +51,22 @@ class WTFTypesTest : public testing::Test {
base::MessageLoop loop_;
};
-} // namespace
-
-TEST_F(WTFTypesTest, WTFToWTFStringSerialization) {
- Array<WTF::String> strs(4);
+WTFArray<WTF::String> ConstructStringArray() {
+ WTFArray<WTF::String> strs(4);
// strs[0] is null.
// strs[1] is empty.
strs[1] = "";
strs[2] = kHelloWorld;
strs[3] = WTF::String::fromUTF8(kUTF8HelloWorld);
- Array<WTF::String> cloned_strs = strs.Clone();
+ return strs;
+}
+
+} // namespace
+
+TEST_F(WTFTypesTest, WTFToWTFSerialization_StringArray) {
+ WTFArray<WTF::String> strs = ConstructStringArray();
+ WTFArray<WTF::String> cloned_strs = strs.Clone();
mojo::internal::SerializationContext context;
size_t size = GetSerializedSize_(cloned_strs, &context);
@@ -68,31 +78,23 @@ TEST_F(WTFTypesTest, WTFToWTFStringSerialization) {
SerializeArray_(std::move(cloned_strs), &buf, &data, &validate_params,
&context);
- Array<WTF::String> strs2;
+ WTFArray<WTF::String> strs2;
Deserialize_(data, &strs2, nullptr);
EXPECT_TRUE(strs.Equals(strs2));
}
-TEST_F(WTFTypesTest, WTFToMojoStringSerialization) {
- Array<WTF::String> strs(4);
- // strs[0] is null.
- // strs[1] is empty.
- strs[1] = "";
- strs[2] = kHelloWorld;
- strs[3] = WTF::String::fromUTF8(kUTF8HelloWorld);
-
- Array<WTF::String> cloned_strs = strs.Clone();
+TEST_F(WTFTypesTest, WTFToMojoSerialization_StringArray) {
+ WTFArray<WTF::String> strs = ConstructStringArray();
mojo::internal::SerializationContext context;
- size_t size = GetSerializedSize_(cloned_strs, &context);
+ size_t size = GetSerializedSize_(strs, &context);
mojo::internal::FixedBufferForTesting buf(size);
mojo::internal::Array_Data<mojo::internal::String_Data*>* data;
mojo::internal::ArrayValidateParams validate_params(
0, true, new mojo::internal::ArrayValidateParams(0, false, nullptr));
- SerializeArray_(std::move(cloned_strs), &buf, &data, &validate_params,
- &context);
+ SerializeArray_(std::move(strs), &buf, &data, &validate_params, &context);
Array<mojo::String> strs2;
Deserialize_(data, &strs2, nullptr);
@@ -108,14 +110,9 @@ TEST_F(WTFTypesTest, SendString) {
blink::TestWTFPtr ptr;
TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr)));
- WTF::String strs[4];
- // strs[0] is null.
- // strs[1] is empty.
- strs[1] = "";
- strs[2] = kHelloWorld;
- strs[3] = WTF::String::fromUTF8(kUTF8HelloWorld);
+ WTFArray<WTF::String> strs = ConstructStringArray();
- for (size_t i = 0; i < arraysize(strs); ++i) {
+ for (size_t i = 0; i < strs.size(); ++i) {
base::RunLoop loop;
// Test that a WTF::String is unchanged after the following conversion:
// - serialized;
@@ -130,5 +127,33 @@ TEST_F(WTFTypesTest, SendString) {
}
}
+TEST_F(WTFTypesTest, SendStringArray) {
+ blink::TestWTFPtr ptr;
+ TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr)));
+
+ WTFArray<WTF::String> arrs[3];
+ // arrs[0] is empty.
+ // arrs[1] is null.
+ arrs[1] = nullptr;
+ arrs[2] = ConstructStringArray();
+
+ for (size_t i = 0; i < arraysize(arrs); ++i) {
+ WTFArray<WTF::String> expected_arr = arrs[i].Clone();
+ base::RunLoop loop;
+ // Test that a mojo::WTFArray<WTF::String> is unchanged after the following
+ // conversion:
+ // - serialized;
+ // - deserialized as mojo::Array<mojo::String>;
+ // - serialized;
+ // - deserialized as mojo::WTFArray<WTF::String>.
+ ptr->EchoStringArray(std::move(arrs[i]),
+ [&loop, &expected_arr, &i](WTFArray<WTF::String> arr) {
+ EXPECT_TRUE(expected_arr.Equals(arr));
+ loop.Quit();
+ });
+ loop.Run();
+ }
+}
+
} // namespace test
} // namespace mojo
diff --git a/mojo/public/cpp/bindings/wtf_array.h b/mojo/public/cpp/bindings/wtf_array.h
new file mode 100644
index 0000000..b5d1a30
--- /dev/null
+++ b/mojo/public/cpp/bindings/wtf_array.h
@@ -0,0 +1,235 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/move.h"
+#include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+#include "mojo/public/cpp/bindings/lib/value_traits.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "third_party/WebKit/Source/wtf/Vector.h"
+
+namespace mojo {
+
+// Represents an array backed by WTF::Vector. Comparing with WTF::Vector,
+// mojo::WTFArray is move-only and can be null.
+// It is easy to convert between WTF::Vector<T> and mojo::WTFArray<T>:
+// - constructor WTFArray(WTF::Vector<T>&&) takes the contents of a
+// WTF::Vector<T>;
+// - method PassStorage() passes the underlying WTF::Vector.
+template <typename T>
+class WTFArray {
+ MOVE_ONLY_TYPE_FOR_CPP_03(WTFArray);
+
+ public:
+ using Data_ =
+ internal::Array_Data<typename internal::WrapperTraits<T>::DataType>;
+ using ElementType = T;
+
+ // Constructs an empty array.
+ WTFArray() : is_null_(false) {}
+ // Constructs a null array.
+ WTFArray(std::nullptr_t null_pointer) : is_null_(true) {}
+
+ // Constructs a new non-null array of the specified size. The elements will
+ // be value-initialized (meaning that they will be initialized by their
+ // default constructor, if any, or else zero-initialized).
+ explicit WTFArray(size_t size) : vec_(size), is_null_(false) {}
+ ~WTFArray() {}
+
+ // Moves the contents of |other| into this array.
+ WTFArray(WTF::Vector<T>&& other) : vec_(std::move(other)), is_null_(false) {}
+ WTFArray(WTFArray&& other) : is_null_(true) { Take(&other); }
+
+ WTFArray& operator=(WTF::Vector<T>&& other) {
+ vec_ = std::move(other);
+ is_null_ = false;
+ return *this;
+ }
+ WTFArray& operator=(WTFArray&& other) {
+ Take(&other);
+ return *this;
+ }
+
+ WTFArray& operator=(std::nullptr_t null_pointer) {
+ is_null_ = true;
+ vec_.clear();
+ return *this;
+ }
+
+ // Creates a non-null array of the specified size. The elements will be
+ // value-initialized (meaning that they will be initialized by their default
+ // constructor, if any, or else zero-initialized).
+ static WTFArray New(size_t size) { return WTFArray(size); }
+
+ // Creates a new array with a copy of the contents of |other|.
+ template <typename U>
+ static WTFArray From(const U& other) {
+ return TypeConverter<WTFArray, U>::Convert(other);
+ }
+
+ // Copies the contents of this array to a new object of type |U|.
+ template <typename U>
+ U To() const {
+ return TypeConverter<U, WTFArray>::Convert(*this);
+ }
+
+ // Indicates whether the array is null (which is distinct from empty).
+ bool is_null() const {
+ // When the array is set to null, the underlying storage |vec_| shouldn't
+ // contain any elements.
+ DCHECK(!is_null_ || vec_.isEmpty());
+ return is_null_;
+ }
+
+ // Indicates whether the array is empty (which is distinct from null).
+ bool empty() const { return vec_.isEmpty() && !is_null_; }
+
+ // Returns a reference to the first element of the array. Calling this on a
+ // null or empty array causes undefined behavior.
+ const T& front() const { return vec_.first(); }
+ T& front() { return vec_.first(); }
+
+ // Returns the size of the array, which will be zero if the array is null.
+ size_t size() const { return vec_.size(); }
+
+ // Returns a reference to the element at zero-based |offset|. Calling this on
+ // an array with size less than |offset|+1 causes undefined behavior.
+ const T& at(size_t offset) const { return vec_.at(offset); }
+ const T& operator[](size_t offset) const { return at(offset); }
+ T& at(size_t offset) { return vec_.at(offset); }
+ T& operator[](size_t offset) { return at(offset); }
+
+ // Resizes the array to |size| and makes it non-null. Otherwise, works just
+ // like the resize method of |WTF::Vector|.
+ void resize(size_t size) {
+ is_null_ = false;
+ vec_.resize(size);
+ }
+
+ // Sets the array to empty (even if previously it was null.)
+ void SetToEmpty() { resize(0); }
+
+ // Returns a const reference to the |WTF::Vector| managed by this class. If
+ // the array is null, this will be an empty vector.
+ const WTF::Vector<T>& storage() const { return vec_; }
+
+ // Passes the underlying storage and resets this array to null.
+ //
+ // TODO(yzshen): Consider changing this to a rvalue-ref-qualified conversion
+ // to WTF::Vector<T> after we move to MSVC 2015.
+ WTF::Vector<T> PassStorage() {
+ is_null_ = true;
+ return std::move(vec_);
+ }
+
+ void Swap(WTFArray* other) {
+ std::swap(is_null_, other->is_null_);
+ vec_.swap(other->vec_);
+ }
+
+ // Swaps the contents of this array with the specified vector, making this
+ // array non-null. Since the vector cannot represent null, it will just be
+ // made empty if this array is null.
+ void Swap(WTF::Vector<T>* other) {
+ is_null_ = false;
+ vec_.swap(*other);
+ }
+
+ // Returns a copy of the array where each value of the new array has been
+ // "cloned" from the corresponding value of this array. If this array contains
+ // primitive data types, this is equivalent to simply copying the contents.
+ // However, if the array contains objects, then each new element is created by
+ // calling the |Clone| method of the source element, which should make a copy
+ // of the element.
+ //
+ // Please note that calling this method will fail compilation if the element
+ // type cannot be cloned (which usually means that it is a Mojo handle type or
+ // a type contains Mojo handles).
+ WTFArray Clone() const {
+ WTFArray result;
+ result.is_null_ = is_null_;
+ CloneTraits<T>::Clone(vec_, &result.vec_);
+ return std::move(result);
+ }
+
+ // Indicates whether the contents of this array are equal to |other|. A null
+ // array is only equal to another null array. Elements are compared using the
+ // |ValueTraits::Equals| method, which in most cases calls the |Equals| method
+ // of the element.
+ bool Equals(const WTFArray& other) const {
+ if (is_null() != other.is_null())
+ return false;
+ if (size() != other.size())
+ return false;
+ for (size_t i = 0; i < size(); ++i) {
+ if (!internal::ValueTraits<T>::Equals(at(i), other.at(i)))
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ typedef WTF::Vector<T> WTFArray::*Testable;
+
+ public:
+ operator Testable() const {
+ // When the array is set to null, the underlying storage |vec_| shouldn't
+ // contain any elements.
+ DCHECK(!is_null_ || vec_.isEmpty());
+ return is_null_ ? 0 : &WTFArray::vec_;
+ }
+
+ private:
+ // Forbid the == and != operators explicitly, otherwise WTFArray will be
+ // converted to Testable to do == or != comparison.
+ template <typename U>
+ bool operator==(const WTFArray<U>& other) const = delete;
+ template <typename U>
+ bool operator!=(const WTFArray<U>& other) const = delete;
+
+ template <typename U,
+ bool is_move_only_type = internal::IsMoveOnlyType<U>::value>
+ struct CloneTraits {};
+
+ template <typename U>
+ struct CloneTraits<U, false> {
+ static inline void Clone(const WTF::Vector<T>& src_vec,
+ WTF::Vector<T>* dest_vec) {
+ DCHECK(dest_vec->isEmpty());
+ dest_vec->reserveCapacity(src_vec.size());
+ for (const auto& element : src_vec)
+ dest_vec->append(element);
+ }
+ };
+
+ template <typename U>
+ struct CloneTraits<U, true> {
+ static inline void Clone(const WTF::Vector<T>& src_vec,
+ WTF::Vector<T>* dest_vec) {
+ DCHECK(dest_vec->isEmpty());
+ dest_vec->reserveCapacity(src_vec.size());
+ for (const auto& element : src_vec)
+ dest_vec->append(element.Clone());
+ }
+ };
+
+ void Take(WTFArray* other) {
+ operator=(nullptr);
+ Swap(other);
+ }
+
+ WTF::Vector<T> vec_;
+ bool is_null_;
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_WTF_ARRAY_H_
diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn
index c9b01b4..18ea38b 100644
--- a/mojo/public/interfaces/bindings/tests/BUILD.gn
+++ b/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -113,10 +113,6 @@ mojom("test_wtf_types_blink") {
"test_wtf_types.mojom",
]
- deps = [
- ":test_wtf_types",
- ]
-
for_blink = true
variant = "blink"
}
diff --git a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
index f776309..9e79a18 100644
--- a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
@@ -7,8 +7,14 @@ module mojo.test;
struct TestWTFCodeGeneration {
string str;
string? nullable_str;
+ array<string> strs;
+ array<string?> nullable_strs;
+ array<array<int32>> arrays;
+ array<bool> bools;
+ array<handle<message_pipe>> handles;
};
interface TestWTF {
EchoString(string? str) => (string? str);
+ EchoStringArray(array<string?>? arr) => (array<string?>? arr);
};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index 8046116e..901fa69 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -19,7 +19,6 @@
#include <ostream>
#include "base/strings/string_piece.h"
-#include "mojo/public/cpp/bindings/array.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
#include "mojo/public/cpp/bindings/associated_interface_request.h"
@@ -39,8 +38,10 @@
#include "{{import.module.path}}.h"
{%- endfor %}
{%- if not for_blink %}
+#include "mojo/public/cpp/bindings/array.h"
#include "mojo/public/cpp/bindings/string.h"
{%- else %}
+#include "mojo/public/cpp/bindings/wtf_array.h"
#include "third_party/WebKit/Source/wtf/text/WTFString.h"
{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 4433740..40b5acc 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -175,7 +175,8 @@ def GetCppArrayArgWrapperType(kind):
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sPtr" % GetNameForKind(kind)
if mojom.IsArrayKind(kind):
- return "mojo::Array<%s> " % GetCppArrayArgWrapperType(kind.kind)
+ pattern = "mojo::WTFArray<%s>" if _for_blink else "mojo::Array<%s>"
+ return pattern % GetCppArrayArgWrapperType(kind.kind)
if mojom.IsMapKind(kind):
return "mojo::Map<%s, %s> " % (GetCppArrayArgWrapperType(kind.key_kind),
GetCppArrayArgWrapperType(kind.value_kind))
@@ -212,7 +213,8 @@ def GetCppResultWrapperType(kind):
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sPtr" % GetNameForKind(kind)
if mojom.IsArrayKind(kind):
- return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
+ pattern = "mojo::WTFArray<%s>" if _for_blink else "mojo::Array<%s>"
+ return pattern % GetCppArrayArgWrapperType(kind.kind)
if mojom.IsMapKind(kind):
return "mojo::Map<%s, %s>" % (GetCppArrayArgWrapperType(kind.key_kind),
GetCppArrayArgWrapperType(kind.value_kind))
@@ -254,7 +256,8 @@ def GetCppWrapperType(kind):
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sPtr" % GetNameForKind(kind)
if mojom.IsArrayKind(kind):
- return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
+ pattern = "mojo::WTFArray<%s>" if _for_blink else "mojo::Array<%s>"
+ return pattern % GetCppArrayArgWrapperType(kind.kind)
if mojom.IsMapKind(kind):
return "mojo::Map<%s, %s>" % (GetCppArrayArgWrapperType(kind.key_kind),
GetCppArrayArgWrapperType(kind.value_kind))
@@ -288,7 +291,8 @@ def GetCppConstWrapperType(kind):
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sPtr" % GetNameForKind(kind)
if mojom.IsArrayKind(kind):
- return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind)
+ pattern = "mojo::WTFArray<%s>" if _for_blink else "mojo::Array<%s>"
+ return pattern % GetCppArrayArgWrapperType(kind.kind)
if mojom.IsMapKind(kind):
return "mojo::Map<%s, %s>" % (GetCppArrayArgWrapperType(kind.key_kind),
GetCppArrayArgWrapperType(kind.value_kind))