#include <iostream>

class Int17Matrix3D {
public:
  Int17Matrix3D(int x, int y, int z) : width_(x), height_(y), depth_(z) {
    arr_ = new int32_t[kNumLenght_ * x * y * z];
    std::memset(arr_, 0, kNumLenght_ * x * y * z * sizeof(int32_t));
  }

  ~Int17Matrix3D() {
    delete[] arr_;
  }

  Int17Matrix3D(const Int17Matrix3D& other) : width_(other.width_), height_(other.height_), depth_(other.depth_) {
    arr_ = new int32_t[kNumLenght_ * width_ * height_ * depth_];
    std::memcpy(arr_, other.arr_, kNumLenght_ * width_ * height_ * depth_ * sizeof(int32_t));
  }

  Int17Matrix3D& operator=(const Int17Matrix3D& other);

  static Int17Matrix3D make_array(int x, int y, int z);

  Int17Matrix3D& operator()(int x, int y, int z);

  int32_t operator()(int x, int y, int z) const;

  void SetElement(int x, int y, int z, int32_t value);

  Int17Matrix3D& operator=(int32_t value);

private:
  const int8_t kNumLenght_ = 17;
  int32_t current_index_;
  int32_t width_;
  int32_t height_;
  int32_t depth_;
  int32_t* arr_;

  bool TakeBit(const int32_t* value, uint32_t bit_position) const;

  Int17Matrix3D& ClearBit(int32_t* value, int32_t bit_position);

  Int17Matrix3D& SetBit(int32_t* value, int32_t bit_position);

  int GetIndex(int x, int y, int z) const;

  int32_t ToDec(const int32_t* arr_, int32_t current_index_) const;

  friend Int17Matrix3D operator+(const Int17Matrix3D& lhs, const Int17Matrix3D& rhs);

  friend Int17Matrix3D operator-(const Int17Matrix3D& lhs, const Int17Matrix3D& rhs);

  friend Int17Matrix3D operator*(const Int17Matrix3D& lhs, const int32_t& rhs);

  friend std::ostream& operator<<(std::ostream& stream, const Int17Matrix3D& array);
};

Int17Matrix3D operator+(const Int17Matrix3D& lhs, const Int17Matrix3D& rhs);

Int17Matrix3D operator-(const Int17Matrix3D& lhs, const Int17Matrix3D& rhs);

Int17Matrix3D operator*(const Int17Matrix3D& lhs, const int32_t& rhs);

std::ostream& operator<<(std::ostream& stream, const Int17Matrix3D& array);



#include <iostream>
#include "Int17Matrix3D.h"

Int17Matrix3D& Int17Matrix3D::operator=(const Int17Matrix3D& other) {
  if (this != &other) {
      delete[] arr_;
      width_ = other.width_;
      height_ = other.height_;
      depth_ = other.depth_;
      arr_ = new int32_t[kNumLenght_ * width_ * height_ * depth_];
      std::memcpy(arr_, other.arr_, kNumLenght_ * width_ * height_ * depth_ * sizeof(int32_t));
  }
  return *this;
} 

Int17Matrix3D make_array(int x, int y, int z) {
  return Int17Matrix3D(x, y, z);
}

Int17Matrix3D& Int17Matrix3D::operator()(int x, int y, int z) {
  current_index_ = GetIndex(x, y, z);
  return *this;
}

int32_t Int17Matrix3D::operator()(int x, int y, int z) const {
  int index = GetIndex(x, y, z);
  return ToDec(arr_, index);
}

void Int17Matrix3D::SetElement(int x, int y, int z, int32_t value) {
    current_index_ = GetIndex(x, y, z);
    (*this) = value;
}

Int17Matrix3D& Int17Matrix3D::operator=(int32_t value) {
  int first_bit_index = current_index_ * kNumLenght_;

  for (int bit = 0; bit < kNumLenght_; ++bit) {
    if (value & (1u << bit)) {
      SetBit(arr_, first_bit_index + bit);
    } else {
      ClearBit(arr_, first_bit_index + bit);
    }
  }
  return *this;
}

bool Int17Matrix3D::TakeBit(const int32_t* value, uint32_t bit_position) const {
  int array_index = bit_position / 32;
  int bit_index = bit_position % 32;
  return ((value[array_index] >> bit_index) & 1) != 0;
}

Int17Matrix3D& Int17Matrix3D::ClearBit(int32_t* value, int32_t bit_position) {
  value[bit_position / 32] &= ~(1 << (bit_position % 32));
  return *this;
  }

Int17Matrix3D& Int17Matrix3D::SetBit(int32_t* value, int32_t bit_position) {
  value[bit_position / 32] |= (1 << (bit_position % 32));
  return *this;
}

int Int17Matrix3D::GetIndex(int x, int y, int z) const {
  return x + y * (width_ * kNumLenght_) + z * (width_ * height_ * kNumLenght_);
}

int32_t Int17Matrix3D::ToDec(const int32_t* arr_, int32_t current_index_) const {
  int first_bit_index = current_index_ * kNumLenght_;
  int32_t decimal_value = 0;
  int32_t exp = 1;

  for (int i = 0; i < kNumLenght_; ++i) {
    if (TakeBit(arr_, first_bit_index + i)) {
      decimal_value += exp;
    }
    exp *= 2;
  }

  return decimal_value;
}

Int17Matrix3D operator+(const Int17Matrix3D& lhs, const Int17Matrix3D& rhs) {
  Int17Matrix3D result(lhs.width_, lhs.height_, lhs.depth_);

  for (int z = 0; z < lhs.depth_; ++z) {
    for (int y = 0; y < lhs.height_; ++y) {
      for (int x = 0; x < lhs.width_; ++x) {
        int index = lhs.GetIndex(x, y, z);

        int val_lhs = lhs.ToDec(lhs.arr_, index);
        int val_rhs = rhs.ToDec(rhs.arr_, index);

        result(x, y, z) = val_lhs + val_rhs;
      }
    }
  }

  return result;
}

Int17Matrix3D operator-(const Int17Matrix3D& lhs, const Int17Matrix3D& rhs) {
  Int17Matrix3D result(lhs.width_, lhs.height_, lhs.depth_);

  for (int z = 0; z < lhs.depth_; ++z) {
    for (int y = 0; y < lhs.height_; ++y) {
      for (int x = 0; x < lhs.width_; ++x) {
        int index = lhs.GetIndex(x, y, z);

        int val_lhs = lhs.ToDec(lhs.arr_, index);
        int val_rhs = rhs.ToDec(rhs.arr_, index);

        result(x, y, z) = val_lhs - val_rhs;
      }
    }
  }

  return result;
}

Int17Matrix3D operator*(const Int17Matrix3D& lhs, const int32_t& rhs) {
  Int17Matrix3D result(lhs.width_, lhs.height_, lhs.depth_);

  for (int z = 0; z < lhs.depth_; ++z) {
    for (int y = 0; y < lhs.height_; ++y) {
      for (int x = 0; x < lhs.width_; ++x) {
        int index = lhs.GetIndex(x, y, z);

        int val_lhs = lhs.ToDec(lhs.arr_, index);

        result(x, y, z) = val_lhs * rhs;
      }
    }
  }

  return result;
}

std::ostream& operator<<(std::ostream& stream, const Int17Matrix3D& array) {
  int32_t decimal_value = array.ToDec(array.arr_, array.current_index_);
  stream << decimal_value;

  return stream;
}


#include <gtest/gtest.h>
#include <lib/Int17Matrix3D.h>

// Test constructor
TEST(Int17Matrix3DTest, Constructor) {
  Int17Matrix3D matrix(2, 2, 2);
  ASSERT_NO_THROW();
}

// Test copy constructor
TEST(Int17Matrix3DTest, CopyConstructor) {
  Int17Matrix3D original(1, 2, 3);
  Int17Matrix3D copy = original;
  ASSERT_NO_THROW();
}

// Test assignment operator
TEST(Int17Matrix3DTest, AssignmentOperator) {
  Int17Matrix3D matrix1(1, 2, 3);
  Int17Matrix3D matrix2(2, 2, 2);
  matrix2 = matrix1;
  ASSERT_NO_THROW();
}

// Test operator()
TEST(Int17Matrix3DTest, ParenthesesOperator) {
  Int17Matrix3D matrix(3, 3, 3);
  matrix(1, 1, 1) = 5; // Assuming values are stored as int17.
  ASSERT_EQ(matrix(1, 1, 1), 5);
}

// Test addition
TEST(Int17Matrix3DTest, Addition) {
  Int17Matrix3D matrix1(1, 1, 1);
  Int17Matrix3D matrix2(1, 1, 1);
  matrix1(0, 0, 0) = 1;
  matrix2(0, 0, 0) = 2;
  Int17Matrix3D matrix3 = matrix1 + matrix2;
  ASSERT_EQ(matrix3(0, 0, 0), 3);
}

// Test substraction
TEST(Int17Matrix3DTest, substraction) {
  Int17Matrix3D matrix1(1, 1, 1);
  Int17Matrix3D matrix2(1, 1, 1);
  matrix1(0, 0, 0) = 1;
  matrix2(0, 0, 0) = 2;
  Int17Matrix3D matrix3 = matrix2 - matrix1;
  ASSERT_EQ(matrix3(0, 0, 0), 1);
}

// Test multiplication
TEST(Int17Matrix3DTest, multiplication) {
  Int17Matrix3D matrix1(1, 1, 1);
  Int17Matrix3D matrix2(1, 1, 1);
  matrix1(0, 0, 0) = 3;
  int mult = 2;
  Int17Matrix3D matrix3 = matrix1 * mult;
  ASSERT_EQ(matrix3(0, 0, 0), 6);
}

[ 64%] Building CXX object tests/CMakeFiles/Int17Matrix3D_test.dir/Int17Matrix3D_test.cpp.o
In file included from /Users/alex/labwork5-SPLOIT47/tests/Int17Matrix3D_test.cpp:1:
/Users/alex/labwork5-SPLOIT47/build/_deps/googletest-src/googletest/include/gtest/gtest.h:1358:11: error: invalid operands to binary expression ('const Int17Matrix3D' and 'const int')
  if (lhs == rhs) {
      ~~~ ^  ~~~
/Users/alex/labwork5-SPLOIT47/build/_deps/googletest-src/googletest/include/gtest/gtest.h:1377:12: note: in instantiation of function template specialization 'testing::internal::CmpHelperEQ<Int17Matrix3D, int>' requested here
    return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
           ^
/Users/alex/labwork5-SPLOIT47/tests/Int17Matrix3D_test.cpp:29:3: note: in instantiation of function template specialization 'testing::internal::EqHelper::Compare<Int17Matrix3D, int, nullptr>' requested here
  ASSERT_EQ(matrix(1, 1, 1), 5);
  ^
/Users/alex/labwork5-SPLOIT47/build/_deps/googletest-src/googletest/include/gtest/gtest.h:1877:31: note: expanded from macro 'ASSERT_EQ'
#define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
                              ^
/Users/alex/labwork5-SPLOIT47/build/_deps/googletest-src/googletest/include/gtest/gtest.h:1861:54: note: expanded from macro 'GTEST_ASSERT_EQ'
  ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
                                                     ^
/Users/alex/labwork5-SPLOIT47/build/_deps/googletest-src/googletest/include/gtest/gtest.h:1350:13: note: candidate function not viable: no known conversion from 'const Int17Matrix3D' to 'testing::internal::faketype' for 1st argument
inline bool operator==(faketype, faketype) { return true; }
            ^
1 error generated.
make[2]: *** [tests/CMakeFiles/Int17Matrix3D_test.dir/Int17Matrix3D_test.cpp.o] Error 1
make[1]: *** [tests/CMakeFiles/Int17Matrix3D_test.dir/all] Error 2
make: *** [all] Error 2


fix it