#ifndef VECTOR_HPP
#define VECTOR_HPP

#include <immintrin.h>
#include <iostream>
#include "debug.hpp"

using namespace std;

using Real = float;

#define AVX_SIZE(n) (n+7)/8


struct Vector{
  #ifdef DEBUG
  size_t n;
  #endif
  Real* data;
  Real& operator[](size_t i);
};

inline Real&
Vector::operator[](size_t i){
  assert(i<n);
  return data[i];
}

inline Vector
init_vector(size_t n){
  Vector v;
  #if DEBUG
  v.n=n;
  #endif
  v.data=static_cast<Real*>(std::aligned_alloc(32,32*AVX_SIZE(n))); //256 bits -> 32 octets
  #if DEGUB
  assert(v.data!=nullptr);
  #endif
  return v;
}

inline void
delete_vector(Vector v){
  free(v.data);
}

inline bool
is_null(Vector v){
  return v.data==nullptr;
}

#if DEBUG
static const Vector NullVector={0,nullptr};
#else
static const Vector NullVector={nullptr};
#endif

inline void
display(Vector v,size_t n){
  if(n==0){
    cout<<"[]"<<endl;
    return;
  }
  cout<<'['<<v[0];
  for(size_t i=1;i<n;++i){
    cout<<','<<v[i];
  }
  cout<<']'<<endl;
}

inline size_t
argmax(Vector v,size_t n){
  assert(n>0);
  size_t imax=0;
  Real vmax=v[0];
  for(size_t i=1;i<n;++i){
    if(v[i]>vmax){
      vmax=v[i];
      imax=i;
    }
  }
  return imax;
}

inline size_t
indice2(size_t i,size_t j,size_t nj){
  return i*nj+j;
}

inline size_t
indice3(size_t i,size_t j,size_t k,size_t nj,size_t nk){
  return (i*nj+j)*nk+k;
}

inline size_t
indice4(size_t i,size_t j,size_t k,size_t l,size_t nj,size_t nk,size_t nl){
  return ((i*nj+j)*nk+k)*nl+l;
}

#endif
