--- /dev/null
+#pragma once
+
+#include "nncc/core/ADT/tensor/Shape.h"
+#include "nncc/core/ADT/tensor/Accessor.h"
+#include "nncc/core/ADT/tensor/Reader.h"
+
+#include "nncc/foundation/ExternalRegion.h"
+
+#include "nnc/core/linalg/TensorVariant.h"
+
+namespace nncc
+{
+namespace contrib
+{
+namespace core
+{
+namespace data
+{
+
+using nncc::core::ADT::tensor::Shape;
+using nncc::core::ADT::tensor::Index;
+using nncc::foundation::ExternalRegion;
+using nncc::core::ADT::tensor::Accessor;
+using nncc::core::ADT::tensor::Reader;
+
+template<typename T>
+class Tensor final : public Accessor<T>, public Reader<T> {
+ public:
+ Tensor() = delete;
+
+ explicit Tensor(const ADT::TensorVariant &t) : _proxy(t), _shape(t.getShape()) {
+ }
+
+ T at(const Index &id) const override {
+ return *reinterpret_cast<T *>(this->_proxy.at(id));
+ }
+
+ T &at(const Index &id) override {
+ return *reinterpret_cast<T *>(this->_proxy.at(id));
+ }
+
+ ExternalRegion<T> getRegion(const Index& idx) {
+ //Only last dimension is safe to process continiously
+ auto lastDim = _shape.rank()- 1;
+ auto base = reinterpret_cast<T *>(_proxy.at(idx));
+ auto length = _shape.dim(lastDim) - idx.at(lastDim);
+ return ExternalRegion<T>(base, length);
+ }
+
+ virtual const Shape &getShape() const { return _proxy.getShape(); };
+
+ private:
+ const ADT::TensorVariant& _proxy;
+ const Shape &_shape;
+};
+
+extern template
+class Tensor<float>;
+
+extern template
+class Tensor<double>;
+
+extern template
+class Tensor<int>;
+
+} // namespace data
+} // namespace core
+} // namespace contrib
+} // namespace nncc