//-----------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------
// ./src/typeDef.h

#ifdef _WIN32
    typedef unsigned char uchar;

    typedef __int8 int8;
    typedef __int16 int16;
    typedef __int32 int32;
    typedef __int64 int64;

    typedef unsigned __int8 uint8;
    typedef unsigned __int16 uint16;
    typedef unsigned __int32 uint32;
    typedef unsigned __int64 uint64;
#else
    #include <stdint.h>

    typedef unsigned char uchar;

    typedef int8_t int8;
    typedef int16_t int16;
    typedef int32_t int32;
    typedef int64_t int64;

    typedef uint8_t uint8;
    typedef uint16_t uint16;
    typedef uint32_t uint32;
    typedef uint64_t uint64;
#endif

#ifndef uint
    typedef unsigned int uint;
#endif

//-----------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------
// ./src/math.hpp

namespace sstd{
    uint8  pow(const uint8 & base, const uint8 & exp);
    uint16 pow(const uint16& base, const uint16& exp);
    uint32 pow(const uint32& base, const uint32& exp);
    uint64 pow(const uint64& base, const uint64& exp);
     float pow(const  float& base, const  float& exp);
    double pow(const double& base, const double& exp);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------
// ./src/math.cpp

#include <cmath>

// base ^ exponent
#define SSTD_DEF_pow_unsigned(T, base, exp)        \
    T b=base, e=exp;                            \
                                                \
    if(e==(T)0){ return (T)1; }                    \
                                                \
    for(; e>(T)0; e>>=1){                        \
        if(e & 1){                                \
            if(e==(T)1){ return b; }            \
            break;                                \
        }                                        \
        b *= b;                                    \
    }                                            \
    T buf = b;                                    \
    buf *= buf;                                    \
    e>>=1;                                        \
                                                \
    for(;;e>>=1){                                \
        if(e & 1){                                \
            b = b * buf;                        \
            if(e==(T)1){ return b; }            \
        }                                        \
        buf *= buf;                                \
    }                                            \
    return b;
uint8  sstd::pow(const uint8 & base, const uint8 & exp){ SSTD_DEF_pow_unsigned(uint8,  base, exp); }
uint16 sstd::pow(const uint16& base, const uint16& exp){ SSTD_DEF_pow_unsigned(uint16, base, exp); }
uint32 sstd::pow(const uint32& base, const uint32& exp){ SSTD_DEF_pow_unsigned(uint32, base, exp); }
uint64 sstd::pow(const uint64& base, const uint64& exp){ SSTD_DEF_pow_unsigned(uint64, base, exp); }
float  sstd::pow(const  float& base, const  float& exp){ return std::pow( (float)base,  (float)exp); }
double sstd::pow(const double& base, const double& exp){ return std::pow((double)base, (double)exp); }

#undef SSTD_DEF_pow_unsigned

//-----------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------
// ./src/stdVector_expansion/stdVector_expansion.hpp

#include <vector>

#define SSTD_DEF_stdVecEx_defInNamespace(Func)                            \
    template <typename T>                   std::vector<T>  Func(const std::vector<T>& lhs, const std::vector<T>& rhs); \
    template <typename T, typename rhsType> std::vector<T>  Func(const std::vector<T>& lhs, const        rhsType& rhs); \
    template <typename T, typename lhsType> std::vector<T>  Func(const        lhsType& lhs, const std::vector<T>& rhs);
#define SSTD_DEF_stdVecEx_defInNamespace_eq(Func)                        \
    template <typename T>                   std::vector<T>& Func(      std::vector<T>& lhs, const std::vector<T>& rhs); \
    template <typename T, typename rhsType> std::vector<T>& Func(      std::vector<T>& lhs, const        rhsType& rhs);

namespace sstd_stdVecEx{
    // operators for mathematics
    SSTD_DEF_stdVecEx_defInNamespace   (add   ); // +
    SSTD_DEF_stdVecEx_defInNamespace_eq(add_eq); // +=
    SSTD_DEF_stdVecEx_defInNamespace   (sub   ); // -
    SSTD_DEF_stdVecEx_defInNamespace_eq(sub_eq); // -=
    SSTD_DEF_stdVecEx_defInNamespace   (mul   ); // *
    SSTD_DEF_stdVecEx_defInNamespace_eq(mul_eq); // *=
    SSTD_DEF_stdVecEx_defInNamespace   (div   ); // /
    SSTD_DEF_stdVecEx_defInNamespace_eq(div_eq); // /=
    SSTD_DEF_stdVecEx_defInNamespace   (mod   ); // %
    SSTD_DEF_stdVecEx_defInNamespace_eq(mod_eq); // %=
    SSTD_DEF_stdVecEx_defInNamespace   (pow   ); // ^
    SSTD_DEF_stdVecEx_defInNamespace_eq(pow_eq); // ^=
    
    // operators for std::vector
    SSTD_DEF_stdVecEx_defInNamespace   (push_back   ); // <<
    SSTD_DEF_stdVecEx_defInNamespace_eq(push_back_eq); // <<=
}

#undef SSTD_DEF_stdVecEx_defInNamespace    // Deletion of used definition, in order not to pollute the namespace
#undef SSTD_DEF_stdVecEx_defInNamespace_eq // Deletion of used definition, in order not to pollute the namespace

//-----------------------------------------------------------------------------------------------------------------------------------------------

// operators for mathematics
#define SSTD_DEF_stdVecEx_o(Func, Ope)                                \
    template <typename T>                                                \
    inline std::vector<T> Func(const std::vector<T>& lhs, const std::vector<T>& rhs){ \
        std::vector<T> ret(lhs.size());                                    \
        for(uint p=0; p<ret.size(); p++){ ret[p]=lhs[p] Ope rhs[p]; }    \
        return ret;                                                        \
    }                                                                    \
    template <typename T, typename rhsType>                                \
    inline std::vector<T> Func(const std::vector<T>& lhs, const rhsType& rhs){ \
        std::vector<T> ret(lhs.size());                                    \
        for(uint p=0; p<ret.size(); p++){ ret[p]=lhs[p] Ope rhs; }        \
        return ret;                                                        \
    }                                                                    \
    template <typename T, typename rhsType>                                \
    inline std::vector<T> Func(const rhsType& lhs, const std::vector<T>& rhs){ \
        std::vector<T> ret(rhs.size());                                    \
        for(uint p=0; p<ret.size(); p++){ ret[p]=lhs Ope rhs[p]; }        \
        return ret;                                                        \
    }
#define SSTD_DEF_stdVecEx_o_eq(Func, Ope)                                \
    template <typename T>                                                \
    inline std::vector<T>& Func(std::vector<T>& lhs, const std::vector<T>& rhs){ \
        for(uint p=0; p<lhs.size(); p++){ lhs[p] Ope rhs[p]; }            \
        return lhs;                                                        \
    }                                                                    \
    template <typename T, typename rhsType>                                \
    inline std::vector<T>& Func(std::vector<T>& lhs, const rhsType& rhs){ \
        for(uint p=0; p<lhs.size(); p++){ lhs[p] Ope rhs; }                \
        return lhs;                                                        \
    }
#define SSTD_DEF_stdVecEx_f(Func, Func2)                                \
    template <typename T>                                                \
    inline std::vector<T> Func(const std::vector<T>& lhs, const std::vector<T>& rhs){ \
        std::vector<T> ret(lhs.size());                                    \
        for(uint p=0; p<ret.size(); p++){ ret[p]=Func2(lhs[p], rhs[p]); } \
        return ret;                                                        \
    }                                                                    \
    template <typename T, typename rhsType>                                \
    inline std::vector<T> Func(const std::vector<T>& lhs, const rhsType& rhs){ \
        std::vector<T> ret(lhs.size());                                    \
        for(uint p=0; p<ret.size(); p++){ ret[p]=Func2(lhs[p], rhs); }    \
        return ret;                                                        \
    }                                                                    \
    template <typename T, typename rhsType>                                \
    inline std::vector<T> Func(const rhsType& lhs, const std::vector<T>& rhs){ \
        std::vector<T> ret(rhs.size());                                    \
        for(uint p=0; p<ret.size(); p++){ ret[p]=Func2(lhs, rhs[p]); }    \
        return ret;                                                        \
    }
#define SSTD_DEF_stdVecEx_f_eq(Func, Func2)                                \
    template <typename T>                                                \
    inline std::vector<T>& Func(std::vector<T>& lhs, const std::vector<T>& rhs){ \
        for(uint p=0; p<lhs.size(); p++){ lhs[p]=Func2(lhs[p], rhs[p]); } \
        return lhs;                                                        \
    }                                                                    \
    template <typename T, typename rhsType>                                \
    inline std::vector<T>& Func(std::vector<T>& lhs, const rhsType& rhs){ \
        for(uint p=0; p<lhs.size(); p++){ lhs[p]=Func2(lhs[p], rhs); }    \
        return lhs;                                                        \
    }
SSTD_DEF_stdVecEx_o   (sstd_stdVecEx::add   , + );
SSTD_DEF_stdVecEx_o_eq(sstd_stdVecEx::add_eq, +=);
SSTD_DEF_stdVecEx_o   (sstd_stdVecEx::sub   , - );
SSTD_DEF_stdVecEx_o_eq(sstd_stdVecEx::sub_eq, -=);
SSTD_DEF_stdVecEx_o   (sstd_stdVecEx::mul   , * );
SSTD_DEF_stdVecEx_o_eq(sstd_stdVecEx::mul_eq, *=);
SSTD_DEF_stdVecEx_o   (sstd_stdVecEx::div   , / );
SSTD_DEF_stdVecEx_o_eq(sstd_stdVecEx::div_eq, /=);
SSTD_DEF_stdVecEx_o   (sstd_stdVecEx::mod   , % );
SSTD_DEF_stdVecEx_o_eq(sstd_stdVecEx::mod_eq, %=);
SSTD_DEF_stdVecEx_f   (sstd_stdVecEx::pow   , sstd::pow); // ^
SSTD_DEF_stdVecEx_f_eq(sstd_stdVecEx::pow_eq, sstd::pow); // ^=
#undef SSTD_DEF_stdVecEx_o    // Deletion of used definition, in order not to pollute the namespace
#undef SSTD_DEF_stdVecEx_o_eq // Deletion of used definition, in order not to pollute the namespace
#undef SSTD_DEF_stdVecEx_f    // Deletion of used definition, in order not to pollute the namespace
#undef SSTD_DEF_stdVecEx_f_eq // Deletion of used definition, in order not to pollute the namespace

//---

// operators for std::vector
template <typename T>
inline std::vector<T> sstd_stdVecEx::push_back(const std::vector<T>& lhs, const std::vector<T>& rhs){
    std::vector<T> ret(lhs.size()+rhs.size());
    uint i=0;
    for(uint p=0; p<lhs.size(); p++){ ret[i]=lhs[p]; i++; }
    for(uint p=0; p<rhs.size(); p++){ ret[i]=lhs[p]; i++; }
    return ret;
}
template <typename T, typename rhsType>
inline std::vector<T> sstd_stdVecEx::push_back(const std::vector<T>& lhs, const rhsType& rhs){
    std::vector<T> ret(lhs.size()+1);
    for(uint p=0; p<lhs.size(); p++){ ret[p]=lhs[p]; }
    ret[lhs.size()]=rhs;
    return ret;
}
template <typename T, typename lhsType>
inline std::vector<T> sstd_stdVecEx::push_back(const lhsType& lhs, const std::vector<T>& rhs){
    std::vector<T> ret(rhs.size()+1);
    ret[0]=lhs;
    for(uint p=0; p<rhs.size(); p++){ ret[p+1]=rhs[p]; }
    return ret;
}

template <typename T>
inline std::vector<T>& sstd_stdVecEx::push_back_eq(std::vector<T>& lhs, const std::vector<T>& rhs){
    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
    return lhs;
}
template <typename T, typename rhsType>
inline std::vector<T>& sstd_stdVecEx::push_back_eq(std::vector<T>& lhs, const rhsType& rhs){
    lhs.push_back(rhs);
    return lhs;
}

//-----------------------------------------------------------------------------------------------------------------------------------------------

#define SSTD_DEF_stdVecEx_Operator(Func, Ope)                            \
    template <typename T>                   inline std::vector<T> operator Ope(const std::vector<T>& lhs, const std::vector<T>& rhs){ return Func<T>         (lhs, rhs); } \
    template <typename T, typename rhsType> inline std::vector<T> operator Ope(const std::vector<T>& lhs, const        rhsType& rhs){ return Func<T, rhsType>(lhs, rhs); } \
    template <typename T, typename lhsType> inline std::vector<T> operator Ope(const        lhsType& lhs, const std::vector<T>& rhs){ return Func<T, lhsType>(lhs, rhs); }
#define SSTD_DEF_stdVecEx_Operator_eq(Func, Ope)                        \
    template <typename T>                   inline std::vector<T>& operator Ope(std::vector<T>& lhs, const std::vector<T>& rhs){ return Func<T>         (lhs, rhs); } \
    template <typename T, typename rhsType> inline std::vector<T>& operator Ope(std::vector<T>& lhs, const        rhsType& rhs){ return Func<T, rhsType>(lhs, rhs); }

// operators for mathematics
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::add   , + );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::add_eq, +=);
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::sub   , - );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::sub_eq, -=);
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::mul   , * );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::mul_eq, *=);
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::div   , / );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::div_eq, /=);
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::mod   , % );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::mod_eq, %=);
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::pow   , ^ );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::pow_eq, ^=);

// operators for std::vector
SSTD_DEF_stdVecEx_Operator   (sstd_stdVecEx::push_back   , << );
SSTD_DEF_stdVecEx_Operator_eq(sstd_stdVecEx::push_back_eq, <<=);

#undef SSTD_DEF_stdVecEx_Operator    // Deletion of used definition, in order not to pollute the namespace
#undef SSTD_DEF_stdVecEx_Operator_eq // Deletion of used definition, in order not to pollute the namespace

//---

template <typename T> inline std::vector<T>& operator++(std::vector<T>& rhs)     { for(uint p=0; p<rhs.size(); p++){ rhs[p]++; } return rhs; } // ++rhs
template <typename T> inline std::vector<T>& operator++(std::vector<T>& rhs, int){ for(uint p=0; p<rhs.size(); p++){ rhs[p]++; } return rhs; } //   rhs++
template <typename T> inline std::vector<T>& operator--(std::vector<T>& rhs)     { for(uint p=0; p<rhs.size(); p++){ rhs[p]--; } return rhs; } // --rhs
template <typename T> inline std::vector<T>& operator--(std::vector<T>& rhs, int){ for(uint p=0; p<rhs.size(); p++){ rhs[p]--; } return rhs; } //   rhs--

//-----------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------
// print.hpp

#include <iostream>

namespace sstd{
    inline void printn_dummy(){}
    
    inline void printn(...){}
    inline void printn_all(...){}
    
    template <typename T>
    inline void for_printn(const std::vector<T>& rhs);
}

#define printn(var) printn_dummy();{printf("%s", #var);sstd::for_printn(var);}
#define printn_all(var) printn_dummy();{printf("%s(%d): ", __func__, __LINE__);printf("%s", #var);sstd::for_printn(var);}

template <typename T>
inline void sstd::for_printn(const std::vector<T>& rhs){
    std::cout<<'['<<rhs.size()<<']';
    std::cout<<" = [ ";
    for(int i=0; i<rhs.size(); i++){ std::cout<<rhs[i]<<' '; }
    std::cout<<"]"<<std::endl;
}

//-----------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------
// main.cpp

int main(){
    std::vector<double> a={1, 2, 3}, b={4, 5, 6};
    sstd::printn(a);
    a*=4;                 // same as "for(int i=0; i<a.size(); i++){ a[i]*=4; }"
    sstd::printn(a);
    printf("\n");
    
    a<<=b;                // same as "a.insert(a.end(), b.begin(), b.end());".
    sstd::printn(a);
    a<<=7.0;              // same as "a.push_back(7.0);".
    sstd::printn(a);
    sstd::printn(a<<8.0); // same as "{ std::vector<double> tmp(a.size()+1); for(uint p=0;p<a.size();p++){tmp[p]=a[p];} tmp[a.size()]=8.0; sstd::printn(tmp); }"
    
    return 0;
}
