--- /dev/null
+#include "core/serialize/Serializer.h"
+#include "model_ir.pb.h"
+
+#include "core/modelIR/ShapeRange.h"
+
+namespace nncc {
+namespace contrib {
+namespace core {
+
+using namespace nncc::contrib::core::data;
+
+template <class T>
+void Serializer<T>::serializeToStream(const T& obj, std::ostream& stream)
+{
+ std::string serializedObject = getSerializedObject(obj);
+ stream.write(serializedObject.c_str(), serializedObject.size());
+}
+
+template <>
+std::string Serializer<Shape>::getSerializedObject (const Shape& shape)
+{
+ proto::TensorShapeProto shapeProto;
+
+ uint32_t rank = shape.rank();
+ for (uint32_t i = 0; i < rank; i++) {
+ shapeProto.add_dims(shape.dim(i));
+ }
+
+ return shapeProto.SerializeAsString();
+}
+
+void setShapeToTensorProto(proto::TensorProto& tensorProto, const Shape& shape)
+{
+ Serializer<Shape> shapeSerializer;
+ tensorProto.mutable_shape()->ParseFromString( shapeSerializer.getSerializedObject( shape ) );
+}
+
+template <>
+std::string Serializer<Tensor<int> >::getSerializedObject (const Tensor<int>& tensor)
+{
+ proto::TensorProto tensorProto;
+ setShapeToTensorProto(tensorProto, tensor.getShape());
+
+ tensorProto.set_dtype(proto::DT_INT32);
+ ShapeRange shapeRange(tensor.getShape());
+ for (auto& idx : shapeRange) {
+ tensorProto.add_int_val(tensor.at(idx));
+ }
+
+ return tensorProto.SerializeAsString();
+}
+
+template <>
+std::string Serializer<Tensor<float> >::getSerializedObject (const Tensor<float>& tensor)
+{
+ proto::TensorProto tensorProto;
+ setShapeToTensorProto(tensorProto, tensor.getShape());
+
+ tensorProto.set_dtype(proto::DataType::DT_FLOAT);
+ ShapeRange shapeRange(tensor.getShape());
+ for (auto& idx : shapeRange) {
+ tensorProto.add_float_val(tensor.at(idx));
+ }
+
+ return tensorProto.SerializeAsString();
+}
+
+template <>
+std::string Serializer<Tensor<double> >::getSerializedObject (const Tensor<double>& tensor)
+{
+ proto::TensorProto tensorProto;
+ setShapeToTensorProto(tensorProto, tensor.getShape());
+
+ tensorProto.set_dtype(proto::DataType::DT_DOUBLE);
+ ShapeRange shapeRange(tensor.getShape());
+ for (auto& idx : shapeRange) {
+ tensorProto.add_double_val(tensor.at(idx));
+ }
+
+ return tensorProto.SerializeAsString();
+}
+
+} // namespace core
+} // namespace contrib
+} // namespace nncc
--- /dev/null
+#include <gtest/gtest.h>
+#include <cmath>
+
+#include "core/serialize/Serializer.h"
+#include "core/modelIR/ShapeRange.h"
+
+using namespace nncc::contrib::core;
+using namespace nncc::contrib::core::data;
+using namespace nncc::contrib::core::ADT;
+
+const double EPS = 0.0000001;
+
+void checkShape(const Shape& shape, const proto::TensorShapeProto& protoShape)
+{
+ ASSERT_EQ(shape.rank(), protoShape.dims_size());
+ for (int i = 0; i < shape.rank(); i++) {
+ ASSERT_EQ(shape.dim(i), protoShape.dims(i));
+ }
+}
+
+TensorVariant allocateIntTensor(const Shape &shape)
+{
+ size_t data_size = 1;
+ for (uint32_t i = 0; i < shape.rank(); ++i)
+ {
+ data_size *= shape.dim(i);
+ }
+
+ auto od = new int[data_size];
+
+ std::shared_ptr<int> data(od, std::default_delete<int>());
+ TensorVariant t(shape, data, TensorVariant::DTYPE::INT);
+
+ return t;
+}
+
+void checkIntTensorContent(const Tensor<int>& tensor, const proto::TensorProto& protoTensor)
+{
+ ASSERT_EQ(protoTensor.dtype(), proto::DataType::DT_INT32);
+ ShapeRange range(tensor.getShape());
+ int i = 0;
+ for (auto& idx : range) {
+ ASSERT_EQ(tensor.at(idx), protoTensor.int_val(i++));
+ }
+}
+
+TensorVariant allocateFloatTensor(const Shape &shape)
+{
+ size_t data_size = 1;
+ for (uint32_t i = 0; i < shape.rank(); ++i)
+ {
+ data_size *= shape.dim(i);
+ }
+
+ auto od = new float[data_size];
+
+ std::shared_ptr<float> data(od, std::default_delete<float>());
+ TensorVariant t(shape, data, TensorVariant::DTYPE::FLOAT);
+
+ return t;
+}
+
+void checkFloatTensorContent(const Tensor<float>& tensor, const proto::TensorProto& protoTensor)
+{
+ ASSERT_EQ(protoTensor.dtype(), proto::DataType::DT_FLOAT);
+ ShapeRange range(tensor.getShape());
+ int i = 0;
+ for (auto& idx : range) {
+ ASSERT_TRUE(fabsf(tensor.at(idx) - protoTensor.float_val(i++)) < EPS);
+ }
+}
+
+TensorVariant allocateDoubleTensor(const Shape &shape)
+{
+ size_t data_size = 1;
+ for (uint32_t i = 0; i < shape.rank(); ++i)
+ {
+ data_size *= shape.dim(i);
+ }
+
+ auto od = new double[data_size];
+
+ std::shared_ptr<double> data(od, std::default_delete<double>());
+ TensorVariant t(shape, data, TensorVariant::DTYPE::FLOAT);
+
+ return t;
+}
+
+void checkDoubleTensorContent(const Tensor<double>& tensor, const proto::TensorProto& protoTensor)
+{
+ ASSERT_EQ(protoTensor.dtype(), proto::DataType::DT_DOUBLE);
+ ShapeRange range(tensor.getShape());
+ int i = 0;
+ for (auto& idx : range) {
+ ASSERT_TRUE(fabs(tensor.at(idx) - protoTensor.double_val(i++)) < EPS);
+ }
+}
+
+
+TEST(Serializer, ShapeSerializationTest) {
+ Serializer<Shape> serializer;
+
+ Shape shape_0{};
+ std::string serializedShape_0 = serializer.getSerializedObject(shape_0);
+ proto::TensorShapeProto protoShape_0;
+ protoShape_0.ParseFromString(serializedShape_0);
+ checkShape(shape_0, protoShape_0);
+
+ Shape shape_1{1};
+ std::string serializedShape_1 = serializer.getSerializedObject(shape_1);
+ proto::TensorShapeProto protoShape_1;
+ protoShape_1.ParseFromString(serializedShape_1);
+ checkShape(shape_1, protoShape_1);
+
+ Shape shape_2{5};
+ std::string serializedShape_2 = serializer.getSerializedObject(shape_2);
+ proto::TensorShapeProto protoShape_2;
+ protoShape_2.ParseFromString(serializedShape_2);
+ checkShape(shape_2, protoShape_2);
+
+ Shape shape_3{2, 4};
+ std::string serializedShape_3 = serializer.getSerializedObject(shape_3);
+ proto::TensorShapeProto protoShape_3;
+ protoShape_3.ParseFromString(serializedShape_3);
+ checkShape(shape_3, protoShape_3);
+
+ Shape shape_4{1, 1, 1, 1};
+ std::string serializedShape_4 = serializer.getSerializedObject(shape_4);
+ proto::TensorShapeProto protoShape_4;
+ protoShape_4.ParseFromString(serializedShape_4);
+ checkShape(shape_4, protoShape_4);
+
+ Shape shape_5{1, 2, 3, 4, 5};
+ std::string serializedShape_5 = serializer.getSerializedObject(shape_5);
+ proto::TensorShapeProto protoShape_5;
+ protoShape_5.ParseFromString(serializedShape_5);
+ checkShape(shape_5, protoShape_5);
+}
+
+TEST(Serializer, IntTensorSerializationTest) {
+ Serializer<Tensor<int>> serializer;
+ int tmp = 0;
+
+ Shape shape_1{3};
+ TensorVariant tv_1(allocateIntTensor(shape_1));
+ Tensor<int> tensor_1(tv_1);
+ for (auto& idx : ShapeRange(shape_1)) {
+ tensor_1.at(idx) = tmp++;
+ }
+ std::string serializedTensor_1 = serializer.getSerializedObject(tensor_1);
+ proto::TensorProto protoTensor_1;
+ protoTensor_1.ParseFromString(serializedTensor_1);
+ checkShape(shape_1, protoTensor_1.shape());
+ checkIntTensorContent(tensor_1, protoTensor_1);
+
+ Shape shape_2{3, 4, 5};
+ TensorVariant tv_2(allocateIntTensor(shape_2));
+ Tensor<int> tensor_2(tv_2);
+ for (auto& idx : ShapeRange(tensor_2.getShape())) {
+ tensor_2.at(idx) = tmp--;
+ }
+ std::string serializedTensor_2 = serializer.getSerializedObject(tensor_2);
+ proto::TensorProto protoTensor_2;
+ protoTensor_2.ParseFromString(serializedTensor_2);
+ checkShape(shape_2, protoTensor_2.shape());
+ checkIntTensorContent(tensor_2, protoTensor_2);
+
+ Shape shape_3{1, 1, 1, 1, 1};
+ TensorVariant tv_3(allocateIntTensor(shape_3));
+ Tensor<int> tensor_3(tv_3);
+ for (auto& idx : ShapeRange(tensor_3.getShape())) {
+ tensor_3.at(idx) = tmp++;
+ }
+ std::string serializedTensor_3 = serializer.getSerializedObject(tensor_3);
+ proto::TensorProto protoTensor_3;
+ protoTensor_3.ParseFromString(serializedTensor_3);
+ checkShape(shape_3, protoTensor_3.shape());
+ checkIntTensorContent(tensor_3, protoTensor_3);
+}
+
+TEST(Serializer, FloatTensorSerializationTest) {
+ Serializer<Tensor<float>> serializer;
+ float tmp = 1.0f;
+
+ Shape shape_1{3};
+ TensorVariant tv_1(allocateFloatTensor(shape_1));
+ Tensor<float> tensor_1(tv_1);
+ for (auto& idx : ShapeRange(tensor_1.getShape())) {
+ tensor_1.at(idx) = tmp;
+ tmp += 10.3f;
+ }
+ std::string serializedTensor_1 = serializer.getSerializedObject(tensor_1);
+ proto::TensorProto protoTensor_1;
+ protoTensor_1.ParseFromString(serializedTensor_1);
+ checkShape(shape_1, protoTensor_1.shape());
+ checkFloatTensorContent(tensor_1, protoTensor_1);
+
+ Shape shape_2{3, 4, 5};
+ TensorVariant tv_2(allocateFloatTensor(shape_2));
+ Tensor<float> tensor_2(tv_2);
+ for (auto& idx : ShapeRange(tensor_2.getShape())) {
+ tensor_2.at(idx) = tmp;
+ tmp *= -1.21f;
+ }
+ std::string serializedTensor_2 = serializer.getSerializedObject(tensor_2);
+ proto::TensorProto protoTensor_2;
+ protoTensor_2.ParseFromString(serializedTensor_2);
+ checkShape(shape_2, protoTensor_2.shape());
+ checkFloatTensorContent(tensor_2, protoTensor_2);
+
+ Shape shape_3{1, 1, 1, 1, 1};
+ TensorVariant tv_3(allocateFloatTensor(shape_3));
+ Tensor<float> tensor_3(tv_3);
+ for (auto& idx : ShapeRange(tensor_3.getShape())) {
+ tmp -= 6.66f;
+ tensor_3.at(idx) = tmp;
+ }
+ std::string serializedTensor_3 = serializer.getSerializedObject(tensor_3);
+ proto::TensorProto protoTensor_3;
+ protoTensor_3.ParseFromString(serializedTensor_3);
+ checkShape(shape_3, protoTensor_3.shape());
+ checkFloatTensorContent(tensor_3, protoTensor_3);
+}
+
+TEST(Serializer, DoubleTensorSerializationTest) {
+ Serializer<Tensor<double>> serializer;
+ double tmp = 1.0f;
+
+ Shape shape_1{3};
+ TensorVariant tv_1(allocateDoubleTensor(shape_1));
+ Tensor<double> tensor_1(tv_1);
+ for (auto& idx : ShapeRange(tensor_1.getShape())) {
+ tensor_1.at(idx) = tmp;
+ tmp += 10.3f;
+ }
+ std::string serializedTensor_1 = serializer.getSerializedObject(tensor_1);
+ proto::TensorProto protoTensor_1;
+ protoTensor_1.ParseFromString(serializedTensor_1);
+ checkShape(shape_1, protoTensor_1.shape());
+ checkDoubleTensorContent(tensor_1, protoTensor_1);
+
+ Shape shape_2{3, 4, 5};
+ TensorVariant tv_2(allocateDoubleTensor(shape_2));
+ Tensor<double> tensor_2(tv_2);
+ for (auto& idx : ShapeRange(tensor_2.getShape())) {
+ tensor_2.at(idx) = tmp;
+ tmp *= -1.21f;
+ }
+ std::string serializedTensor_2 = serializer.getSerializedObject(tensor_2);
+ proto::TensorProto protoTensor_2;
+ protoTensor_2.ParseFromString(serializedTensor_2);
+ checkShape(shape_2, protoTensor_2.shape());
+ checkDoubleTensorContent(tensor_2, protoTensor_2);
+
+ Shape shape_3{1, 1, 1, 1, 1};
+ TensorVariant tv_3(allocateDoubleTensor(shape_3));
+ Tensor<double> tensor_3(tv_3);
+ for (auto& idx : ShapeRange(tensor_3.getShape())) {
+ tmp -= 6.66f;
+ tensor_3.at(idx) = tmp;
+ }
+ std::string serializedTensor_3 = serializer.getSerializedObject(tensor_3);
+ proto::TensorProto protoTensor_3;
+ protoTensor_3.ParseFromString(serializedTensor_3);
+ checkShape(shape_3, protoTensor_3.shape());
+ checkDoubleTensorContent(tensor_3, protoTensor_3);
+}