Convert (by copying) hidl_array from and to std::array.
* For example, hidl_array<T, 2, 3> can be converted to
std::array<std::array<T, 3>, 2>.
* Uses operator= for copying.
* Also uses operator= when initializing an hidl_array
(instead of memcpy'ing). This fixes potential memory
issues for hidl_array<hidl_string>, for example.
Bug: 32883329
Test: libhidl_test
Change-Id: Idf7d080433aaed2c585fd4875f3411e5544a9e72
diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h
index f9f7f32..7d649ef 100644
--- a/base/include/hidl/HidlSupport.h
+++ b/base/include/hidl/HidlSupport.h
@@ -18,6 +18,7 @@
#define ANDROID_HIDL_SUPPORT_H
#include <algorithm>
+#include <array>
#include <dirent.h>
#include <dlfcn.h>
#include <iterator>
@@ -453,7 +454,20 @@
};
template<typename T, size_t SIZE1, size_t... SIZES>
+ struct std_array {
+ using type = std::array<typename std_array<T, SIZES...>::type, SIZE1>;
+ };
+
+ template<typename T, size_t SIZE1>
+ struct std_array<T, SIZE1> {
+ using type = std::array<T, SIZE1>;
+ };
+
+ template<typename T, size_t SIZE1, size_t... SIZES>
struct accessor {
+
+ using std_array_type = typename std_array<T, SIZE1, SIZES...>::type;
+
explicit accessor(T *base)
: mBase(base) {
}
@@ -463,12 +477,22 @@
&mBase[index * product<SIZES...>::value]);
}
+ accessor &operator=(const std_array_type &other) {
+ for (size_t i = 0; i < SIZE1; ++i) {
+ (*this)[i] = other[i];
+ }
+ return *this;
+ }
+
private:
T *mBase;
};
template<typename T, size_t SIZE1>
struct accessor<T, SIZE1> {
+
+ using std_array_type = typename std_array<T, SIZE1>::type;
+
explicit accessor(T *base)
: mBase(base) {
}
@@ -477,12 +501,22 @@
return mBase[index];
}
+ accessor &operator=(const std_array_type &other) {
+ for (size_t i = 0; i < SIZE1; ++i) {
+ (*this)[i] = other[i];
+ }
+ return *this;
+ }
+
private:
T *mBase;
};
template<typename T, size_t SIZE1, size_t... SIZES>
struct const_accessor {
+
+ using std_array_type = typename std_array<T, SIZE1, SIZES...>::type;
+
explicit const_accessor(const T *base)
: mBase(base) {
}
@@ -492,12 +526,23 @@
&mBase[index * product<SIZES...>::value]);
}
+ operator std_array_type() {
+ std_array_type array;
+ for (size_t i = 0; i < SIZE1; ++i) {
+ array[i] = (*this)[i];
+ }
+ return array;
+ }
+
private:
const T *mBase;
};
template<typename T, size_t SIZE1>
struct const_accessor<T, SIZE1> {
+
+ using std_array_type = typename std_array<T, SIZE1>::type;
+
explicit const_accessor(const T *base)
: mBase(base) {
}
@@ -506,6 +551,14 @@
return mBase[index];
}
+ operator std_array_type() {
+ std_array_type array;
+ for (size_t i = 0; i < SIZE1; ++i) {
+ array[i] = (*this)[i];
+ }
+ return array;
+ }
+
private:
const T *mBase;
};
@@ -514,10 +567,27 @@
////////////////////////////////////////////////////////////////////////////////
+// A multidimensional array of T's. Assumes that T::operator=(const T &) is defined.
template<typename T, size_t SIZE1, size_t... SIZES>
struct hidl_array {
+
+ using std_array_type = typename details::std_array<T, SIZE1, SIZES...>::type;
+
hidl_array() = default;
+ // Copies the data from source, using T::operator=(const T &).
+ hidl_array(const T *source) {
+ for (size_t i = 0; i < elementCount(); ++i) {
+ mBuffer[i] = source[i];
+ }
+ }
+
+ // Copies the data from the given std::array, using T::operator=(const T &).
+ hidl_array(const std_array_type &array) {
+ details::accessor<T, SIZE1, SIZES...> modifier(mBuffer);
+ modifier = array;
+ }
+
T *data() { return mBuffer; }
const T *data() const { return mBuffer; }
@@ -537,17 +607,36 @@
return std::make_tuple(SIZE1, SIZES...);
}
+ static constexpr size_t elementCount() {
+ return details::product<SIZE1, SIZES...>::value;
+ }
+
+ operator std_array_type() const {
+ return details::const_accessor<T, SIZE1, SIZES...>(mBuffer);
+ }
+
private:
- T mBuffer[details::product<SIZE1, SIZES...>::value];
+ T mBuffer[elementCount()];
};
+// An array of T's. Assumes that T::operator=(const T &) is defined.
template<typename T, size_t SIZE1>
struct hidl_array<T, SIZE1> {
+
+ using std_array_type = typename details::std_array<T, SIZE1>::type;
+
hidl_array() = default;
+
+ // Copies the data from source, using T::operator=(const T &).
hidl_array(const T *source) {
- memcpy(mBuffer, source, SIZE1 * sizeof(T));
+ for (size_t i = 0; i < elementCount(); ++i) {
+ mBuffer[i] = source[i];
+ }
}
+ // Copies the data from the given std::array, using T::operator=(const T &).
+ hidl_array(const std_array_type &array) : hidl_array(array.data()) {}
+
T *data() { return mBuffer; }
const T *data() const { return mBuffer; }
@@ -560,6 +649,16 @@
}
static constexpr size_t size() { return SIZE1; }
+ static constexpr size_t elementCount() { return SIZE1; }
+
+ // Copies the data to an std::array, using T::operator=(T).
+ operator std_array_type() const {
+ std_array_type array;
+ for (size_t i = 0; i < SIZE1; ++i) {
+ array[i] = mBuffer[i];
+ }
+ return array;
+ }
private:
T mBuffer[SIZE1];
diff --git a/test_main.cpp b/test_main.cpp
index 276b3a4..3ee8bc9 100644
--- a/test_main.cpp
+++ b/test_main.cpp
@@ -23,6 +23,8 @@
#include <vector>
#define EXPECT_ARRAYEQ(__a1__, __a2__, __size__) EXPECT_TRUE(isArrayEqual(__a1__, __a2__, __size__))
+#define EXPECT_2DARRAYEQ(__a1__, __a2__, __size1__, __size2__) \
+ EXPECT_TRUE(is2dArrayEqual(__a1__, __a2__, __size1__, __size2__))
template<typename T, typename S>
static inline bool isArrayEqual(const T arr1, const S arr2, size_t size) {
@@ -32,6 +34,15 @@
return true;
}
+template<typename T, typename S>
+static inline bool is2dArrayEqual(const T arr1, const S arr2, size_t size1, size_t size2) {
+ for(size_t i = 0; i < size1; i++)
+ for (size_t j = 0; j < size2; j++)
+ if(arr1[i][j] != arr2[i][j])
+ return false;
+ return true;
+}
+
class LibHidlTest : public ::testing::Test {
public:
virtual void SetUp() override {
@@ -175,6 +186,29 @@
great(v);
}
+TEST_F(LibHidlTest, StdArrayTest) {
+ using android::hardware::hidl_array;
+ hidl_array<int32_t, 5> array{(int32_t[5]){1, 2, 3, 4, 5}};
+ std::array<int32_t, 5> stdArray = array;
+ EXPECT_ARRAYEQ(array.data(), stdArray.data(), 5);
+ hidl_array<int32_t, 5> array2 = stdArray;
+ EXPECT_ARRAYEQ(array.data(), array2.data(), 5);
+}
+
+TEST_F(LibHidlTest, MultiDimStdArrayTest) {
+ using android::hardware::hidl_array;
+ hidl_array<int32_t, 2, 3> array;
+ for (size_t i = 0; i < 2; i++) {
+ for (size_t j = 0; j < 3; j++) {
+ array[i][j] = i + j + i * j;
+ }
+ }
+ std::array<std::array<int32_t, 3>, 2> stdArray = array;
+ EXPECT_2DARRAYEQ(array, stdArray, 2, 3);
+ hidl_array<int32_t, 2, 3> array2 = stdArray;
+ EXPECT_2DARRAYEQ(array, array2, 2, 3);
+}
+
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();