From: Sangwan Kwon Date: Mon, 18 Nov 2019 04:32:48 +0000 (+0900) Subject: Add archive as serializer X-Git-Tag: submit/tizen/20200810.073515~159 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2e9628cc778117d874c45bbe33716e232cb0b478;p=platform%2Fcore%2Fsecurity%2Fvist.git Add archive as serializer Signed-off-by: Sangwan Kwon --- diff --git a/CMakeLists.txt b/CMakeLists.txt index ff2dedf..41aeea6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,13 +55,9 @@ ADD_DEFINITIONS(-DOSQUERY_VERSION=${OSQUERY_VERSION} -DOSQUERY_BUILD_VERSION=${OSQUERY_VERSION} -DOSQUERY_BUILD_SDK_VERSION=${OSQUERY_VERSION}) -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/api") INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src") INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/tools/sqlite3") INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/osquery/include") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/vist/tsqb") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/osquery/extensions/thrift/gen") INCLUDE_DIRECTORIES("/usr/local/include") ENABLE_TESTING() diff --git a/src/vist/archive.hpp b/src/vist/archive.hpp new file mode 100644 index 0000000..3d72296 --- /dev/null +++ b/src/vist/archive.hpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/* + * @file archive.hpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @brief Define archive interface for serializer and parameter-pack. + * @details 1. Serializer: Serialize/deserialize below types. + * (fundamental types, archival object, unique_ptr, shared_ptr) + * 2. Parameter-pack: Pack/unpack zero or more template arguments. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace vist { + +class Archival; + +template +using IsFundamental = typename std::enable_if::value, int>::type; + +template +using IsArchival = typename std::enable_if::value, int>::type; + +class Archive { +public: + virtual ~Archive() = default; + + template + void pack(const Front& front, const Rest&... rest); + inline void pack(void) {} + + template + void unpack(Front& front, Rest&... rest); + inline void unpack(void) {} + + template + void transform(std::tuple& tuple); + + // serialize method + template = 0> + Archive& operator<<(const T& value); + template = 0> + Archive& operator<<(const T& object); + template + Archive& operator<<(const std::unique_ptr& pointer); + template + Archive& operator<<(const std::shared_ptr& pointer); + Archive& operator<<(const std::string& value); + Archive& operator<<(const Archive& archive); + + // deserialize method + template = 0> + Archive& operator>>(T& value); + template = 0> + Archive& operator>>(T& object); + template + Archive& operator>>(std::unique_ptr& pointer); + template + Archive& operator>>(std::shared_ptr& pointer); + Archive& operator>>(std::string& value); + Archive& operator>>(Archive& archive); + + unsigned char* get(void) noexcept; + std::size_t size(void) const noexcept; + void reserve(std::size_t size) noexcept; + +protected: + virtual void save(const void* bytes, std::size_t size); + virtual void load(void* bytes, std::size_t size); + +private: + template + void transformImpl(T& tuple, EmptySequence); + template + void transformImpl(T& tuple, IndexSequence); + + std::vector buffer; + std::size_t current = 0; +}; + +class Archival { +public: + virtual ~Archival() = default; + + virtual void pack(Archive& archive) const = 0; + virtual void unpack(Archive& archive) = 0; +}; + +template +void Archive::pack(const Front& front, const Rest&... rest) +{ + *this << front; + this->pack(rest...); +} + +template +void Archive::unpack(Front& front, Rest&... rest) +{ + *this >> front; + this->unpack(rest...); +} + +template +void Archive::transform(std::tuple& tuple) +{ + constexpr auto size = std::tuple_size>::value; + this->transformImpl(tuple, make_index_sequence()); +} + +template +void Archive::transformImpl(T& tuple, EmptySequence) +{ +} + +template +void Archive::transformImpl(T& tuple, IndexSequence) +{ + this->unpack(std::get(tuple)...); +} + +template> +Archive& Archive::operator<<(const T& value) +{ + this->save(reinterpret_cast(&value), sizeof(value)); + + return *this; +} + +template +Archive& Archive::operator<<(const std::unique_ptr& pointer) +{ + return *this << *pointer; +} + +template +Archive& Archive::operator<<(const std::shared_ptr& pointer) +{ + return *this << *pointer; +} + +template> +Archive& Archive::operator<<(const T& object) +{ + object.pack(*this); + + return *this; +} + +template> +Archive& Archive::operator>>(T& value) +{ + this->load(reinterpret_cast(&value), sizeof(value)); + + return *this; +} + +template +Archive& Archive::operator>>(std::unique_ptr& pointer) +{ + if (pointer == nullptr) + pointer.reset(new T); + + return *this >> *pointer; +} + +template +Archive& Archive::operator>>(std::shared_ptr& pointer) +{ + if (pointer == nullptr) + pointer.reset(new T); + + return *this >> *pointer; +} + +template> +Archive& Archive::operator>>(T& object) +{ + object.unpack(*this); + + return *this; +} + +} // namespace vist diff --git a/src/vist/common/CMakeLists.txt b/src/vist/common/CMakeLists.txt index c76ae24..9f0766b 100644 --- a/src/vist/common/CMakeLists.txt +++ b/src/vist/common/CMakeLists.txt @@ -16,7 +16,8 @@ PKG_CHECK_MODULES(VIST_COMMON_DEPS REQUIRED gflags klay dlog) INCLUDE_DIRECTORIES(SYSTEM . ${VIST_COMMON_DEPS_INCLUDE_DIRS}) -ADD_VIST_COMMON_LIBRARY(vist_common common.cpp) +ADD_VIST_COMMON_LIBRARY(vist_common archive.cpp + common.cpp) FILE(GLOB COMMON_TESTS "tests/*.cpp") ADD_VIST_TEST(${COMMON_TESTS}) diff --git a/src/vist/common/archive.cpp b/src/vist/common/archive.cpp new file mode 100644 index 0000000..1458309 --- /dev/null +++ b/src/vist/common/archive.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/* + * @file archive.cpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @brief Implementation of archive. + */ + +#include + +#include +#include +#include + +namespace vist { + +Archive& Archive::operator<<(const Archive& archive) +{ + auto data = archive.buffer; + auto index = archive.current; + std::copy(data.begin() + index, data.end(), std::back_inserter(this->buffer)); +} + +Archive& Archive::operator<<(const std::string& value) +{ + std::size_t size = value.size(); + this->save(reinterpret_cast(&size), sizeof(size)); + this->save(reinterpret_cast(value.c_str()), value.size()); + + return *this; +} + +Archive& Archive::operator>>(Archive& archive) +{ + auto data = this->buffer; + auto index = this->current; + std::copy(data.begin() + index, data.end(), std::back_inserter(archive.buffer)); +} + +Archive& Archive::operator>>(std::string& value) +{ + std::size_t size; + this->load(reinterpret_cast(&size), sizeof(size)); + + value.resize(size); + this->load(reinterpret_cast(&value.front()), size); + + return *this; +} + +unsigned char* Archive::get(void) noexcept +{ + return this->buffer.data(); +} + +std::size_t Archive::size(void) const noexcept +{ + return this->buffer.size(); +} + +void Archive::reserve(std::size_t size) noexcept +{ + this->buffer.reserve(size); +} + +void Archive::save(const void* bytes, std::size_t size) +{ + auto binary = reinterpret_cast(const_cast(bytes)); + std::vector next(binary, binary + size); + std::copy(next.begin(), next.end(), std::back_inserter(this->buffer)); +} + +void Archive::load(void* bytes, std::size_t size) +{ + std::memcpy(bytes, reinterpret_cast(this->buffer.data() + current), size); + current += size; +} + +} // namespace vist diff --git a/src/vist/common/tests/archive.cpp b/src/vist/common/tests/archive.cpp new file mode 100644 index 0000000..ab8c69b --- /dev/null +++ b/src/vist/common/tests/archive.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + +#include + +#include +#include +#include +#include + +using namespace vist; + +TEST(ArchiveTests, serializer_fundamental_int) +{ + int input1 = std::numeric_limits::lowest(); + int input2 = std::numeric_limits::max(); + + Archive archive; + archive << input1 << input2; + + int output1, output2; + archive >> output1 >> output2; + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); +} + +TEST(ArchiveTests, serializer_fundamental_float) +{ + float input1 = std::numeric_limits::lowest(); + float input2 = std::numeric_limits::max(); + + Archive archive; + archive << input1 << input2; + + float output1, output2; + archive >> output1 >> output2; + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); +} + +TEST(ArchiveTests, serializer_fundamental_double) +{ + double input1 = std::numeric_limits::lowest(); + double input2 = std::numeric_limits::max(); + + Archive archive; + archive << input1 << input2; + + double output1, output2; + archive >> output1 >> output2; + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); +} + +TEST(ArchiveTests, serializer_fundamental_long_long_int) +{ + long long int input1 = std::numeric_limits::lowest(); + long long int input2 = std::numeric_limits::max(); + + Archive archive; + archive << input1 << input2; + + long long int output1, output2; + archive >> output1 >> output2; + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); +} + +TEST(ArchiveTests, serializer_fundamental_bool) +{ + bool input1 = true; + bool input2 = false; + + Archive archive; + archive << input1 << input2; + + bool output1, output2; + archive >> output1 >> output2; + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); +} + +TEST(ArchiveTests, serializer_fundamental_char) +{ + char input1 = 'a'; + char input2 = 'Z'; + + Archive archive; + archive << input1 << input2; + + char output1, output2; + archive >> output1 >> output2; + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); +} + +TEST(ArchiveTests, serializer_fundamental_nullptr) +{ + std::nullptr_t input; + + Archive archive; + archive << input; + + std::nullptr_t output; + archive >> output; + + assert(input == output); +} + +TEST(ArchiveTests, serializer_fundamental_reference) +{ + int input = std::numeric_limits::max(); + int& refInput = input; + + Archive archive; + archive << refInput; + + int output; + int& refOutput = output; + archive >> refOutput; + + EXPECT_EQ(input, output); + EXPECT_EQ(refInput, refOutput); +} + +struct Object : public Archival { + void pack(Archive& archive) const override + { + archive << a << b << c; + } + + void unpack(Archive& archive) override + { + archive >> a >> b >> c; + } + + int a = 0; + bool b = true; + std::string c = "str"; +}; + +TEST(ArchiveTests, archival) +{ + Object input; + input.a = 100; + input.b = false; + input.c = "archival string"; + + Archive archive; + archive << input; + + Object output; + archive >> output; + + EXPECT_EQ(input.a, output.a); + EXPECT_EQ(input.b, output.b); + EXPECT_EQ(input.c, output.c); +} + +TEST(ArchiveTests, string) +{ + std::string input = "Archive string test"; + + Archive archive; + archive << input; + + std::string output; + archive >> output; + + EXPECT_EQ(input, output); +} + +TEST(ArchiveTests, unique_ptr) +{ + std::unique_ptr input(new bool(true)); + + Archive archive; + archive << input; + + std::unique_ptr output; + archive >> output; + + EXPECT_EQ(*input, *output); +} + +TEST(ArchiveTests, shared_ptr) +{ + std::shared_ptr input = std::make_shared(); + *input = "Archive string test"; + + Archive archive; + archive << input; + + std::shared_ptr output; + archive >> output; + + EXPECT_EQ(*input, *output); +} + +TEST(ArchiveTests, archive) +{ + std::string input1 = "Archive string test1"; + std::string input2 = "Archive string test2"; + std::string input3 = "Archive string test3"; + + Archive archive1, archive2, archive3; + archive1 << input1; + archive2 << input2; + archive3 << input3; + + archive1 << archive2; + archive1 >> archive3; + + std::string output1; + std::string output2; + std::string output3; + archive3 >> output1 >> output2 >> output3; + + EXPECT_EQ(output1, input3); + EXPECT_EQ(output2, input1); + EXPECT_EQ(output3, input2); +} + +TEST(ArchiveTests, parameter_pack) +{ + int input1 = std::numeric_limits::max(); + float input2 = std::numeric_limits::max(); + double input3 = std::numeric_limits::max(); + std::string input4 = "Archive string test"; + std::unique_ptr input5(new bool(true)); + + Archive archive; + archive.pack(input1, input2, input3, input4, input5); + + int output1; + float output2; + double output3; + std::string output4; + std::unique_ptr output5; + + archive.unpack(output1, output2, output3, output4, output5); + + EXPECT_EQ(input1, output1); + EXPECT_EQ(input2, output2); + EXPECT_EQ(input3, output3); + EXPECT_EQ(input4, output4); + EXPECT_EQ(*input5, *output5); +} + +TEST(ArchiveTests, parameter_pack_empty) +{ + Archive archive; + archive.pack(); + + archive.unpack(); +} + +TEST(ArchiveTests, parameter_pack_transform) +{ + int input1 = std::numeric_limits::max(); + float input2 = std::numeric_limits::max(); + double input3 = std::numeric_limits::max(); + std::string input4 = "Archive string test"; + std::shared_ptr input5(new bool(true)); + + Archive archive; + archive.pack(input1, input2, input3, input4, input5); + + int output1; + float output2; + double output3; + std::string raw; + std::string& output4 = raw; + std::shared_ptr output5; + + auto tuple = std::make_tuple(output1, output2, output3, output4, output5); + archive.transform(tuple); + + EXPECT_EQ(input1, std::get<0>(tuple)); + EXPECT_EQ(input2, std::get<1>(tuple)); + EXPECT_EQ(input3, std::get<2>(tuple)); + EXPECT_EQ(input4, std::get<3>(tuple)); + EXPECT_EQ(*input5, *(std::get<4>(tuple))); +} + +TEST(ArchiveTests, parameter_pack_transform_empty) +{ + auto tuple = std::make_tuple(); + Archive archive; + archive.transform(tuple); +} diff --git a/src/vist/index-sequence.hpp b/src/vist/index-sequence.hpp new file mode 100644 index 0000000..170c2c9 --- /dev/null +++ b/src/vist/index-sequence.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/* + * @file index-sequence.hpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @brief Generate index sequence. + */ + +#pragma once + +#include + +namespace vist { + +struct EmptySequence {}; + +template +struct IndexSequence {}; + +namespace { + +template +struct SequenceExpansion : SequenceExpansion {}; + +template +struct SequenceExpansion<0, S...> { using Type = IndexSequence; }; + +template<> +struct SequenceExpansion<0> { using Type = EmptySequence; }; + +} // anonymous namespace + +template +using make_index_sequence = typename SequenceExpansion::Type; + +} // namespace vist