# Seperate file to make it easier to include separately from REPL for running pieces
using VectorizationBase, OffsetArrays
using VectorizationBase: data
using Test

const W64S = VectorizationBase.pick_vector_width(Float64)
const W64 = Int(VectorizationBase.register_size() ÷ sizeof(Float64))
const W32 = Int(VectorizationBase.register_size() ÷ sizeof(Float32))
const VE = Core.VecElement
randnvec(N = Val{W64}()) = Vec(ntuple(_ -> Core.VecElement(randn()), N))
function tovector(u::VectorizationBase.VecUnroll{_N,W,_T}) where {_N,W,_T}
    T = _T === VectorizationBase.Bit ? Bool : _T
    N = _N + 1; i = 0
    x = Vector{T}(undef, N * W)
    for n ∈ 1:N
        v = VectorizationBase.data(u)[n]
        for w ∈ 0:W-1
            x[(i += 1)] = VectorizationBase.extractelement(v, w)
        end
    end
    x
end
tovector(v::VectorizationBase.AbstractSIMDVector{W}) where {W} = [VectorizationBase.extractelement(v,w) for w ∈ 0:W-1]
tovector(v::VectorizationBase.LazyMulAdd) = tovector(VectorizationBase._materialize(v))
tovector(x) = x
tovector(i::MM{W,X}) where {W,X} = collect(range(data(i), step = X, length = W))
tovector(i::MM{W,X,I}) where {W,X,I<:Union{Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64}} = collect(range(data(i), step = I(X), length = I(W)))
A = randn(13, 17); L = length(A); M, N = size(A);

trunc_int(x::Integer, ::Type{T}) where {T} = x % T
trunc_int(x, ::Type{T}) where {T} = x
size_trunc_int(x::Signed, ::Type{T}) where {T} = signed(x % T)
size_trunc_int(x::Unsigned, ::Type{T}) where {T} = unsigned(x % T)
size_trunc_int(x, ::Type{T}) where {T} = x

check_within_limits(x, y) = @test x ≈ y
function check_within_limits(x::Vector{T}, y) where {T <: Integer}
    if Bool(VectorizationBase.has_feature(Val(:x86_64_avx512dq)))
        return @test x ≈ y
    end
    r = typemin(Int32) .≤ y .≤ typemax(Int32)
    xs = x[r]; ys = y[r]
    @test xs ≈ ys
end

maxi(a,b) = max(a,b)
mini(a,b) = min(a,b)
function maxi(a::T1,b::T2) where {T1<:Base.BitInteger,T2<:Base.BitInteger}
    T = promote_type(T1,T2)
    T(a > b ? a : b)
end
function mini(a::T1,b::T2) where {T1<:Base.BitInteger,T2<:Base.BitInteger}
    _T = promote_type(T1,T2)
    T = if T1 <: Signed || T2 <: Signed
        signed(_T)
    else
        _T
    end
    T(a < b ? a : b)
end
maxi_fast(a,b) = Base.FastMath.max_fast(a,b)
mini_fast(a,b) = Base.FastMath.min_fast(a,b)
maxi_fast(a::Base.BitInteger, b::Base.BitInteger) = maxi(a, b)
mini_fast(a::Base.BitInteger, b::Base.BitInteger) = mini(a, b)

include("accuracy.jl")

nothing

