<commit_before>#include <iostream> //cout
#include <cstdlib>	//rand, sran
#include <string>
#include "complex_matrices.h"
#include <gmc.h> 	//LaGenMatComplex
#include <laslv.h>  //LUFactorizeIP, LaLUInverseIP, etc.
#include <blas3pp.h>
//#include <random>   //random_device, mt19937

using namespace std;

/* Total [13/20] */

int ran(int a, int b){
//    random_device rd;
//    mt19937 gen(rd());
//    uniform_int_distribution<> dist(a, b);
//    return dist(gen);
    return rand() % b;
}

/* Printing [6/9] */
void print_scalar(const COMPLEX scalar){
    cout << scalar << endl;
}                                                 //working
void print_scalar(const COMPLEX scalar, const string name){
    cout << name << ":" << scalar << endl;
}                              //working
void print_array(const COMPLEX array[], int len){
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                                        //working
void print_array(const COMPLEX array[], int len, const string name){
	cout << name << ":" << endl;
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                     //working
void print_matrix(const LaGenMatComplex& matrix){
	cout << matrix << endl;
}                                        //working
void print_matrix(const LaGenMatComplex& matrix, const string name){
	cout << name << ":" << endl << matrix << endl;
}			          //working

/* Number generation [2/2] */
void generate_scalar(COMPLEX& A, const int x){
    A.r = ran(1, x);	//1 to x
    A.i = ran(1, x);
}               //working
void generate_scalar(int number, const int x){
    number = ran(1, x);	//1 to x
}                                                //working
void generate_array(COMPLEX array[], const int len, const int x){
    for(int i = 0; i < len; i++){
        array[i].r = ran(1, x);	//1 to x
        array[i].i = ran(1, x);
	}
}                        //working

/* Matrix conversion [3/3] */
void vec_to_array(const LaVectorComplex& vector, const int len, COMPLEX array[ ]){
    for(int i = 0; i < len; i++){
        array[i] = vector(i);
    }
}       //working
void array_to_diag(COMPLEX array[], const int len, LaGenMatComplex& diag){
    diag = 0;
    for(int i = 0; i < len; i++){
        diag(i, i) = array[i];
    }
}               //working
void vec_to_diag(const LaVectorComplex& vector, const int len, LaGenMatComplex& diag){
    COMPLEX array[len];
    vec_to_array(vector, len, array);
    array_to_diag(array, len, diag);
}   //working

/* Scalar manipulation [5/8] */
int factorial(int x){
	if(x <= 1){
        return 1;
	}else{
        return x * factorial(x - 1);
	}
}                                                                    //working
void scalar_addition(const COMPLEX& A, const COMPLEX& B , COMPLEX& result){
    result.r = A.r + B.r;
    result.i = A.i + B.i;
}              //working
void scalar_addition(COMPLEX& result, const COMPLEX addition){
    result.r += addition.r;
    result.i += addition.i;
}
void scalar_multiplication(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r * B;
    result.i = A.i * B;
}              //to test
void scalar_multiplication(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA * laB;
    result = laResult.toCOMPLEX();
}         //to test
void scalar_product(COMPLEX& total, const COMPLEX& number){
    COMPLEX part;
    part.r = (total.r * number.r) - (total.i * number.i);
    part.i = (total.r * number.i) + (total.i * number.r);
    total = part;
}
void scalar_division(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r / B;
    result.i = A.i / B;
}                    //to test
void scalar_division(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA / laB;
    result = laResult.toCOMPLEX();
}               //to test
void scalar_powers(const COMPLEX& number, const int power, COMPLEX& result){
    la::complex<double> laResult = la::complex<double>(number);
    la::complex<double> laNumber = la::complex<double>(number);
    for(int i = 1; i < power; i++){
        laResult *= laNumber;
    }
    result = laResult.toCOMPLEX();
}             //to test
void scalar_exponential_main(const COMPLEX& number, const int iterations, COMPLEX& result){
    COMPLEX division, total_division;
    result.r = 1;
    result.i = 0 ;
    for(int step = 1; step <= iterations; step++){   //sum (from 1 to n)
        total_division.r = 1;
        total_division.i = 0;
        for(int i = 1; i <= step; i++){        //    ( num^n / n!)
            scalar_division(number, i, division);
            scalar_product(total_division, division);
        }
        scalar_addition(result, total_division);
    }
}
void scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    //COMPLEX power;
    //COMPLEX division;
    //result.r = 0;
    //result.i = 0;
    //for(int i = 0; i < iter; i++){
    //    scalar_powers(number, i, power);
    //    scalar_division(power, factorial(i), division);
    //    scalar_addition(result, division, result);
    //}
}         //empty
//COMPLEX rec_scalar_exp_step(const COMPLEX& number, const int step){
//    COMPLEX result, division, multiplication;
//	if(step <= 1){
//        result.r = 1;
//        return result;
//	}else{
//        scalar_division(number,step,division);
//        scalar_multiplication(division, rec_scalar_exp_step(step-1),  multiplication);
//        return multiplication;
//	}
//}
void recursive_scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    //COMPLEX power;
    //COMPLEX division;
    //result.r = 0;
    //result.i = 0;
    //for(int i = 0; i < iter; i++){
    //    scalar_powers(number, i, power);
    //    scalar_division(power, factorial(i), division);
    //    scalar_addition(result, division, result);
    //}
} //empty

/* array manipulation [0/1] */
void array_powers(COMPLEX array[], const int len, const int power){/**/
    /*
    for(int i = 0; i < len; i++){
        array[i] = complex_power(array[i], power, result);
    }
    */
}                       //empty

/* Matrix manipulation [2/4] */
void diagonal_matrix_powers(){      //empty
  //...
}
void matrix_eigenvstuff(const LaGenMatComplex& matrix, LaVectorComplex& eigenvalues, LaGenMatComplex& eigenvectors){ //working
    //LaEigSolve: http://lapackpp.sourceforge.net/html/laslv_8h.html#086357d17e9cdcaec69ab7db76998769
    LaEigSolve(matrix, eigenvalues, eigenvectors);
}
void matrix_inverse(LaGenMatComplex& matrix, int len){                                                               //working
    // LaLUInverseIP: http://lapackpp.sourceforge.net/html/laslv_8h.html#a042c82c5b818f54e7f000d068f14189
    LaVectorLongInt PIV = LaVectorLongInt(len);
    LUFactorizeIP(matrix, PIV);
    LaLUInverseIP(matrix, PIV);
}
void matrix_exp_step(){                                 //empty
    //
}
void matrix_exponential(const LaGenMatComplex& eigenvectors, const LaGenMatComplex& eigenvalues){
    //LaGenMatComplex step = LaGenMatComplex

} //empty

/* Testing [3/3] */
void test_scalar_manipulation(const int max_rand){
    COMPLEX compA;
    generate_scalar(compA, max_rand);
    COMPLEX compB;
    generate_scalar(compB, max_rand);
    int realB;
    generate_scalar(realB, max_rand);
    COMPLEX result;

    cout << "compA = " << compA << endl;
    cout << "compB = " << compB << endl;
    cout << "realB = " << realB << endl;
    cout << endl;

    for(int i = 1; i < 5; i++){                                                 //factorials
        cout << "factorial(" << i << "): " << factorial(i) << endl;
    }

    scalar_addition(compA, compB, result);                                      //addition/subtraction
    cout << "scalar addition: " << result << endl << endl;

    scalar_multiplication(compA, realB, result);                                //multiplication
    cout << "scalar multiplication by scalar: " << result << endl << endl;

    scalar_multiplication(compA, compB, result);
    cout << "scalar multiplication by complex: " << result << endl << endl;

    scalar_division(compA, realB, result);         //division
    cout << "scalar division by scalar: " << result << endl << endl;

    scalar_division(compA, compB, result);
    cout << "scalar division by complex: " << result << endl << endl;

    for(int i = 1; i < 5; i++){
        scalar_powers(compA, i, result);
        cout << "scalar powers - A^" << i << " = " << result << endl;
    }
    cout << endl;

    COMPLEX sum;
    sum.r = 0;
    sum.i = 0;
    for(int i = 0; i < 5; i++){
        cout << "sum(" << i << ") = " << sum << endl;
        scalar_addition(sum, compA);
    }
    cout << "sum = " << sum << endl;

}                                       //to test
void test_eigenvalues(const LaGenMatComplex& initialMatrix, const int size){
    LaVectorComplex eigenvalueVec = LaVectorComplex(size);             //initialise eigenstuff
    LaGenMatComplex eigenvalues = LaGenMatComplex::zeros(size, size);
    LaGenMatComplex eigenvectors = LaGenMatComplex::zeros(size, size);
    matrix_eigenvstuff(initialMatrix, eigenvalueVec, eigenvectors); //calculate eigenstuff
    print_matrix(eigenvalueVec, "eigenvalue vector");               //print eigenstuff
    vec_to_diag(eigenvalueVec, size, eigenvalues);
    print_matrix(eigenvalues, "eigenvalue matrix");
    print_matrix(eigenvectors, "eigenvector matrix");
}             //to test
void test_inverse(const LaGenMatComplex& initialMatrix, const int size){
    LaGenMatComplex inverseMatrix;
    inverseMatrix = initialMatrix.copy();
    matrix_inverse(inverseMatrix, size);
    print_matrix(inverseMatrix, "inverse matrix");
}                 //to test
void test_scalar_sum(const int max_rand, const int iterations){
    COMPLEX number, step;
    generate_scalar(number, max_rand);
    step = number;
    for(int i = 0; i < iterations; i++){
        cout << step << endl;
        scalar_addition(number, step);
    }
    cout << number << endl;
}
void test_scalar_product(const int max_rand, const int iterations){
    //...
}
void test_scalar_exponential(const int iterations, const int max_rand){
    COMPLEX number, result;
    generate_scalar(number, max_rand);
    cout << endl << "scalar exponential test no.: " << number << endl << endl;
    scalar_exponential_main(number, iterations, result);
    cout << "e^" << number << " = " << result << endl;
}
void test_matrix_exponential(const LaGenMatComplex& initialMatrix, const int size){
    //...
}
void test_idenpotent_exponential(){

    // Generate the matrix
    int elements [] = {2, -2, -4, -1, 3, 4, 1, -2, -3};
    COMPLEX comp[9];
    for(int i = 0; i < 9; i++){
        comp[i].r = elements[i];
        comp[i].i = 0;
    }
    LaGenMatComplex initialMatrix = LaGenMatComplex(comp, 3, 3, false );
    cout << "initialMatrix = " << endl << initialMatrix << endl;

    //calculate the exponential
}

/* Main Program */
int main(){
//	int matrix_size = 3, max_rand = 9;
//    int matrix_volume = matrix_size * matrix_size;

	/* generate the matrix */
//    COMPLEX elements[matrix_volume];
//    generate_array(elements, matrix_volume, max_rand);
//	LaGenMatComplex initialMatrix = LaGenMatComplex(elements, matrix_size, matrix_size, false );

//    print_matrix(initialMatrix, "initial matrix");

    /* test eigenvalues */
//    test_eigenvalues(initialMatrix, matrix_size);

    /* test scalar manipulation */
//    test_scalar_manipulation(4);

    /* test scalar product */

    /* test scalar exponentials */
    test_scalar_exponential(5000,40);
//    test_idenpotent_exponential();

    /* test inversion */
//    test_inverse(initialMatrix, matrix_size);
}
<commit_msg>testing matrix exponentials - WIP<commit_after>#include <iostream> //cout
#include <cstdlib>	//rand, sran
#include <string>
#include "complex_matrices.h"
#include <gmc.h> 	//LaGenMatComplex
#include <laslv.h>  //LUFactorizeIP, LaLUInverseIP, etc.
#include <blas3pp.h>
//#include <random>   //random_device, mt19937

using namespace std;

/* Total [13/20] */

int ran(int a, int b){
//    random_device rd;
//    mt19937 gen(rd());
//    uniform_int_distribution<> dist(a, b);
//    return dist(gen);
    return rand() % b;
}

/* Printing [6/9] */
void print_scalar(const COMPLEX scalar){
    cout << scalar << endl;
}                                                 //working
void print_scalar(const COMPLEX scalar, const string name){
    cout << name << ":" << scalar << endl;
}                              //working
void print_array(const COMPLEX array[], int len){
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                                        //working
void print_array(const COMPLEX array[], int len, const string name){
	cout << name << ":" << endl;
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                     //working
void print_matrix(const LaGenMatComplex& matrix){
	cout << matrix << endl;
}                                        //working
void print_matrix(const LaGenMatComplex& matrix, const string name){
	cout << name << ":" << endl << matrix << endl;
}			          //working

/* Number generation [2/2] */
void generate_scalar(COMPLEX& A, const int x){
    A.r = ran(1, x);	//1 to x
    A.i = ran(1, x);
}               //working
void generate_scalar(int number, const int x){
    number = ran(1, x);	//1 to x
}                                                //working
void generate_array(COMPLEX array[], const int len, const int x){
    for(int i = 0; i < len; i++){
        array[i].r = ran(1, x);	//1 to x
        array[i].i = ran(1, x);
	}
}                        //working

/* Matrix conversion [3/3] */
void vec_to_array(const LaVectorComplex& vector, const int len, COMPLEX array[ ]){
    for(int i = 0; i < len; i++){
        array[i] = vector(i);
    }
}       //working
void array_to_diag(COMPLEX array[], const int len, LaGenMatComplex& diag){
    diag = 0;
    for(int i = 0; i < len; i++){
        diag(i, i) = array[i];
    }
}               //working
void vec_to_diag(const LaVectorComplex& vector, const int len, LaGenMatComplex& diag){
    COMPLEX array[len];
    vec_to_array(vector, len, array);
    array_to_diag(array, len, diag);
}   //working

/* Scalar manipulation [5/8] */
int factorial(int x){
	if(x <= 1){
        return 1;
	}else{
        return x * factorial(x - 1);
	}
}                                                                    //working
void scalar_addition(const COMPLEX& A, const COMPLEX& B , COMPLEX& result){
    result.r = A.r + B.r;
    result.i = A.i + B.i;
}              //working
void scalar_addition(COMPLEX& result, const COMPLEX addition){
    result.r += addition.r;
    result.i += addition.i;
}
void scalar_multiplication(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r * B;
    result.i = A.i * B;
}              //to test
void scalar_multiplication(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA * laB;
    result = laResult.toCOMPLEX();
}         //to test
void scalar_product(COMPLEX& total, const COMPLEX& number){
    COMPLEX part;
    part.r = (total.r * number.r) - (total.i * number.i);
    part.i = (total.r * number.i) + (total.i * number.r);
    total = part;
}
void scalar_division(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r / B;
    result.i = A.i / B;
}                    //to test
void scalar_division(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA / laB;
    result = laResult.toCOMPLEX();
}               //to test
void scalar_powers(const COMPLEX& number, const int power, COMPLEX& result){
    la::complex<double> laResult = la::complex<double>(number);
    la::complex<double> laNumber = la::complex<double>(number);
    for(int i = 1; i < power; i++){
        laResult *= laNumber;
    }
    result = laResult.toCOMPLEX();
}             //to test
void scalar_exponential_main(const COMPLEX& number, const int iterations, COMPLEX& result){
    COMPLEX division, total_division;
    result.r = 1;
    result.i = 0 ;
    for(int step = 1; step <= iterations; step++){   //sum (from 1 to n)
        total_division.r = 1;
        total_division.i = 0;
        for(int i = 1; i <= step; i++){        //    ( num^n / n!)
            scalar_division(number, i, division);
            scalar_product(total_division, division);
        }
        scalar_addition(result, total_division);
    }
}
void scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    //COMPLEX power;
    //COMPLEX division;
    //result.r = 0;
    //result.i = 0;
    //for(int i = 0; i < iter; i++){
    //    scalar_powers(number, i, power);
    //    scalar_division(power, factorial(i), division);
    //    scalar_addition(result, division, result);
    //}
}         //empty
//COMPLEX rec_scalar_exp_step(const COMPLEX& number, const int step){
//    COMPLEX result, division, multiplication;
//	if(step <= 1){
//        result.r = 1;
//        return result;
//	}else{
//        scalar_division(number,step,division);
//        scalar_multiplication(division, rec_scalar_exp_step(step-1),  multiplication);
//        return multiplication;
//	}
//}
void recursive_scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    //COMPLEX power;
    //COMPLEX division;
    //result.r = 0;
    //result.i = 0;
    //for(int i = 0; i < iter; i++){
    //    scalar_powers(number, i, power);
    //    scalar_division(power, factorial(i), division);
    //    scalar_addition(result, division, result);
    //}
} //empty

/* array manipulation [0/1] */
void array_powers(COMPLEX array[], const int len, const int power){/**/
    /*
    for(int i = 0; i < len; i++){
        array[i] = complex_power(array[i], power, result);
    }
    */
}                       //empty

/* Matrix manipulation [2/4] */
void diagonal_matrix_powers(){      //empty
  //...
}
void matrix_eigenvstuff(const LaGenMatComplex& matrix, LaVectorComplex& eigenvalues, LaGenMatComplex& eigenvectors){ //working
    //LaEigSolve: http://lapackpp.sourceforge.net/html/laslv_8h.html#086357d17e9cdcaec69ab7db76998769
    LaEigSolve(matrix, eigenvalues, eigenvectors);
}
void matrix_inverse(LaGenMatComplex& matrix, int len){                                                               //working
    // LaLUInverseIP: http://lapackpp.sourceforge.net/html/laslv_8h.html#a042c82c5b818f54e7f000d068f14189
    LaVectorLongInt PIV = LaVectorLongInt(len);
    LUFactorizeIP(matrix, PIV);
    LaLUInverseIP(matrix, PIV);
}
void matrix_exp_step(){                                 //empty
    //
}
void matrix_exponential(const LaGenMatComplex& eigenvectors, const LaGenMatComplex& eigenvalues){
    //LaGenMatComplex step = LaGenMatComplex

} //empty

/* Testing [3/3] */
void test_scalar_manipulation(const int max_rand){
    COMPLEX compA;
    generate_scalar(compA, max_rand);
    COMPLEX compB;
    generate_scalar(compB, max_rand);
    int realB;
    generate_scalar(realB, max_rand);
    COMPLEX result;

    cout << "compA = " << compA << endl;
    cout << "compB = " << compB << endl;
    cout << "realB = " << realB << endl;
    cout << endl;

    for(int i = 1; i < 5; i++){                                                 //factorials
        cout << "factorial(" << i << "): " << factorial(i) << endl;
    }

    scalar_addition(compA, compB, result);                                      //addition/subtraction
    cout << "scalar addition: " << result << endl << endl;

    scalar_multiplication(compA, realB, result);                                //multiplication
    cout << "scalar multiplication by scalar: " << result << endl << endl;

    scalar_multiplication(compA, compB, result);
    cout << "scalar multiplication by complex: " << result << endl << endl;

    scalar_division(compA, realB, result);         //division
    cout << "scalar division by scalar: " << result << endl << endl;

    scalar_division(compA, compB, result);
    cout << "scalar division by complex: " << result << endl << endl;

    for(int i = 1; i < 5; i++){
        scalar_powers(compA, i, result);
        cout << "scalar powers - A^" << i << " = " << result << endl;
    }
    cout << endl;

    COMPLEX sum;
    sum.r = 0;
    sum.i = 0;
    for(int i = 0; i < 5; i++){
        cout << "sum(" << i << ") = " << sum << endl;
        scalar_addition(sum, compA);
    }
    cout << "sum = " << sum << endl;

}                                       //to test
void test_eigenvalues(const LaGenMatComplex& initialMatrix, const int size){
    LaVectorComplex eigenvalueVec = LaVectorComplex(size);             //initialise eigenstuff
    LaGenMatComplex eigenvalues = LaGenMatComplex::zeros(size, size);
    LaGenMatComplex eigenvectors = LaGenMatComplex::zeros(size, size);
    matrix_eigenvstuff(initialMatrix, eigenvalueVec, eigenvectors); //calculate eigenstuff
    print_matrix(eigenvalueVec, "eigenvalue vector");               //print eigenstuff
    vec_to_diag(eigenvalueVec, size, eigenvalues);
    print_matrix(eigenvalues, "eigenvalue matrix");
    print_matrix(eigenvectors, "eigenvector matrix");
}             //to test
void test_inverse(const LaGenMatComplex& initialMatrix, const int size){
    LaGenMatComplex inverseMatrix;
    inverseMatrix = initialMatrix.copy();
    matrix_inverse(inverseMatrix, size);
    print_matrix(inverseMatrix, "inverse matrix");
}                 //to test
void test_scalar_sum(const int max_rand, const int iterations){
    COMPLEX number, step;
    generate_scalar(number, max_rand);
    step = number;
    for(int i = 0; i < iterations; i++){
        cout << step << endl;
        scalar_addition(number, step);
    }
    cout << number << endl;
}
void test_scalar_product(const int max_rand, const int iterations){
    //...
}
void test_scalar_exponential(const int iterations, const int max_rand){
    COMPLEX number, result;
    generate_scalar(number, max_rand);
    cout << endl << "scalar exponential test no.: " << number << endl << endl;
    scalar_exponential_main(number, iterations, result);
    cout << "e^" << number << " = " << result << endl;
}
void test_matrix_exponential(const LaGenMatComplex& initialMatrix, const int size){
    cout << "intial matrix = " << endl << initialMatrix << endl;
}
void test_idenpotent_exponential(){

    // Generate the matrix
    int elements [] = {2, -2, -4, -1, 3, 4, 1, -2, -3};
    COMPLEX comp[9];
    for(int i = 0; i < 9; i++){
        comp[i].r = elements[i];
        comp[i].i = 0;
    }
    LaGenMatComplex initialMatrix = LaGenMatComplex(comp, 3, 3, false );
    cout << "initialMatrix = " << endl << initialMatrix << endl;

    //calculate the exponential
}

/* Main Program */
int main(){
//	int matrix_size = 3, max_rand = 9;
//    int matrix_volume = matrix_size * matrix_size;

	/* generate the matrix */
//    COMPLEX elements[matrix_volume];
//    generate_array(elements, matrix_volume, max_rand);
//	LaGenMatComplex initialMatrix = LaGenMatComplex(elements, matrix_size, matrix_size, false );

//    print_matrix(initialMatrix, "initial matrix");

    /* test eigenvalues */
//    test_eigenvalues(initialMatrix, matrix_size);

    /* test scalar manipulation */
//    test_scalar_manipulation(4);

    /* test scalar product */

    /* test scalar exponentials */
//    test_scalar_exponential(5000,40);
//    test_idenpotent_exponential();

    /* test matrix exponentials */
    test_matrix_exponential(initialMatrix, matrix_size);
    /* test inversion */
//    test_inverse(initialMatrix, matrix_size);
}
<|endoftext|>


<commit_before>//
// snowflake.hpp
// *************
//
// Copyright (c) 2019 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/fwd.hpp"
#include "aegis/config.hpp"
#include <nlohmann/json.hpp>

namespace aegis
{

/// Stores creation time and extra data specific to Discord for entities
class snowflake
{
public:
    constexpr snowflake() noexcept : _id(0) {}
    constexpr snowflake(int64_t _snowflake) noexcept : _id(_snowflake) {}
    constexpr snowflake(const snowflake & _snowflake) noexcept : _id(_snowflake._id) {}
    explicit snowflake(const char * _snowflake) noexcept : _id(std::stoll(std::string(_snowflake))) {}
    explicit snowflake(const std::string & _snowflake) noexcept : _id(std::stoll(_snowflake)) {}
#if defined(AEGIS_CXX17)
    explicit snowflake(const std::string_view _snowflake) noexcept : _id(std::stoll(std::string{ _snowflake })) {}
#endif
    explicit snowflake(const nlohmann::json & _snowflake) noexcept : _id(std::stoll(_snowflake.get<std::string>())) {}
    AEGIS_DECL snowflake(const aegis::guild & _guild) noexcept;
    AEGIS_DECL snowflake(const aegis::channel & _channel) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::role & _role) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::message & _message) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::emoji & _emoji) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::attachment & _attachment) noexcept;

    constexpr operator int64_t() const noexcept
    {
        return _id;
    }

    /// Retrieve full snowflake value
    /**
     * @returns int64_t Snowflake
     */
    constexpr int64_t get() const noexcept
    {
        return _id;
    };

    /// Obtain all the snowflake values as a tuple
    /**
     * @returns std::tuple of all the snowflake parts
     */
    constexpr std::tuple<int64_t, int8_t, int8_t, int16_t> get_all() const noexcept
    {
        return std::tuple<int64_t, int8_t, int8_t, int16_t>{ get_timestamp(), get_worker(), get_process(), get_count() };
    };

    ///
    /**
     * @returns int16_t Internal counter for snowflakes
     */
    constexpr int16_t get_count() const noexcept
    {
        return static_cast<int16_t>(_id & _countMask);
    };

    ///
    /**
     * @returns int8_t Process ID of the snowflake generator
     */
    constexpr int8_t get_process() const noexcept
    {
        return static_cast<int8_t>((_id & _workerMask) >> 12);
    };

    ///
    /**
     * @returns int8_t Worker ID of the snowflake generator
     */
    constexpr int8_t get_worker() const noexcept
    {
        return static_cast<int8_t>((_id & _workerMask) >> 17);
    };

    ///
    /**
     * @returns int64_t The Discord epoch timestamp this snowflake was generated
     */
    constexpr int64_t get_timestamp() const noexcept
    {
        return (_id & _timestampMask) >> 22;
    };

    /// Obtain all the snowflake values as a tuple
    /**
     * @returns std::tuple of all the snowflake parts
     */
    static constexpr std::tuple<int64_t, int8_t, int8_t, int16_t> c_get_all(int64_t _snowflake) noexcept
    {
        return std::tuple<int64_t, int8_t, int8_t, int16_t>{ c_get_timestamp(_snowflake), c_get_worker(_snowflake), c_get_process(_snowflake), c_get_count(_snowflake) };
    };

    ///
    /**
     * @returns int16_t Internal counter for snowflakes
     */
    static constexpr int16_t c_get_count(int64_t _snowflake) noexcept
    {
        return static_cast<int16_t>(_snowflake & _countMask);
    };

    ///
    /**
     * @returns int8_t Process ID of the snowflake generator
     */
    static constexpr int8_t c_get_process(int64_t _snowflake) noexcept
    {
        return static_cast<int8_t>((_snowflake & _workerMask) >> 12);
    };

    ///
    /**
     * @returns int8_t Worker ID of the snowflake generator
     */
    static constexpr int8_t c_get_worker(int64_t _snowflake) noexcept
    {
        return static_cast<int8_t>((_snowflake & _workerMask) >> 17);
    };

    ///
    /**
     * @returns int64_t The Discord epoch timestamp this snowflake was generated
     */
    static constexpr int64_t c_get_timestamp(int64_t _snowflake) noexcept
    {
        return (_snowflake & _timestampMask) >> 22;
    };

    ///
    /**
     * @returns int64_t Unix timestamp this snowflake was generated
     */
    constexpr int64_t get_time() const noexcept
    {
        return get_timestamp() + _discordEpoch;
    };

    ///
    /**
     * @returns int64_t Unix timestamp this snowflake was generated
     */
    static constexpr int64_t c_get_time(int64_t _snowflake) noexcept
    {
        return c_get_timestamp(_snowflake) + _discordEpoch;
    };

private:
    uint64_t _id;
    static constexpr uint64_t _countMask = 0x0000000000000FFFL;
    static constexpr uint64_t _processMask = 0x000000000001F000L;
    static constexpr uint64_t _workerMask = 0x00000000003E0000L;
    static constexpr uint64_t _timestampMask = 0xFFFFFFFFFFC00000L;
    static constexpr uint64_t _discordEpoch = 1420070400000;
};

/// \cond TEMPLATES
AEGIS_DECL void from_json(const nlohmann::json& j, snowflake& s);
AEGIS_DECL void to_json(nlohmann::json& j, const snowflake& s);
/// \endcond

}

/// \cond TEMPLATES
namespace std
{

template <>
struct hash<aegis::snowflake>
{
    std::size_t operator()(const aegis::snowflake& k) const
    {
        return hash<int64_t>()(k.get());
    }
};

}
/// \endcond

#if defined(AEGIS_HEADER_ONLY)
#include "aegis/impl/snowflake.cpp"
#endif
<commit_msg>Added snowflake::gets() for string representation of snowflake<commit_after>//
// snowflake.hpp
// *************
//
// Copyright (c) 2019 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/fwd.hpp"
#include "aegis/config.hpp"
#include <nlohmann/json.hpp>

namespace aegis
{

/// Stores creation time and extra data specific to Discord for entities
class snowflake
{
public:
    constexpr snowflake() noexcept : _id(0) {}
    constexpr snowflake(int64_t _snowflake) noexcept : _id(_snowflake) {}
    constexpr snowflake(const snowflake & _snowflake) noexcept : _id(_snowflake._id) {}
    explicit snowflake(const char * _snowflake) noexcept : _id(std::stoll(std::string(_snowflake))) {}
    explicit snowflake(const std::string & _snowflake) noexcept : _id(std::stoll(_snowflake)) {}
#if defined(AEGIS_CXX17)
    explicit snowflake(const std::string_view _snowflake) noexcept : _id(std::stoll(std::string{ _snowflake })) {}
#endif
    explicit snowflake(const nlohmann::json & _snowflake) noexcept : _id(std::stoll(_snowflake.get<std::string>())) {}
    AEGIS_DECL snowflake(const aegis::guild & _guild) noexcept;
    AEGIS_DECL snowflake(const aegis::channel & _channel) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::role & _role) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::message & _message) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::emoji & _emoji) noexcept;
    AEGIS_DECL snowflake(const aegis::gateway::objects::attachment & _attachment) noexcept;

    constexpr operator int64_t() const noexcept
    {
        return _id;
    }

    /// Get snowflake as int64_t
    /**
     * @returns int64_t Snowflake
     */
    constexpr int64_t get() const noexcept
    {
        return _id;
    };

    /// Get snowflake as std::string
    /**
     * @returns std::string Snowflake
     */
    std::string gets() const noexcept
    {
        return std::to_string(_id);
    };

    /// Obtain all the snowflake values as a tuple
    /**
     * @returns std::tuple of all the snowflake parts
     */
    constexpr std::tuple<int64_t, int8_t, int8_t, int16_t> get_all() const noexcept
    {
        return std::tuple<int64_t, int8_t, int8_t, int16_t>{ get_timestamp(), get_worker(), get_process(), get_count() };
    };

    ///
    /**
     * @returns int16_t Internal counter for snowflakes
     */
    constexpr int16_t get_count() const noexcept
    {
        return static_cast<int16_t>(_id & _countMask);
    };

    ///
    /**
     * @returns int8_t Process ID of the snowflake generator
     */
    constexpr int8_t get_process() const noexcept
    {
        return static_cast<int8_t>((_id & _workerMask) >> 12);
    };

    ///
    /**
     * @returns int8_t Worker ID of the snowflake generator
     */
    constexpr int8_t get_worker() const noexcept
    {
        return static_cast<int8_t>((_id & _workerMask) >> 17);
    };

    ///
    /**
     * @returns int64_t The Discord epoch timestamp this snowflake was generated
     */
    constexpr int64_t get_timestamp() const noexcept
    {
        return (_id & _timestampMask) >> 22;
    };

    /// Obtain all the snowflake values as a tuple
    /**
     * @returns std::tuple of all the snowflake parts
     */
    static constexpr std::tuple<int64_t, int8_t, int8_t, int16_t> c_get_all(int64_t _snowflake) noexcept
    {
        return std::tuple<int64_t, int8_t, int8_t, int16_t>{ c_get_timestamp(_snowflake), c_get_worker(_snowflake), c_get_process(_snowflake), c_get_count(_snowflake) };
    };

    ///
    /**
     * @returns int16_t Internal counter for snowflakes
     */
    static constexpr int16_t c_get_count(int64_t _snowflake) noexcept
    {
        return static_cast<int16_t>(_snowflake & _countMask);
    };

    ///
    /**
     * @returns int8_t Process ID of the snowflake generator
     */
    static constexpr int8_t c_get_process(int64_t _snowflake) noexcept
    {
        return static_cast<int8_t>((_snowflake & _workerMask) >> 12);
    };

    ///
    /**
     * @returns int8_t Worker ID of the snowflake generator
     */
    static constexpr int8_t c_get_worker(int64_t _snowflake) noexcept
    {
        return static_cast<int8_t>((_snowflake & _workerMask) >> 17);
    };

    ///
    /**
     * @returns int64_t The Discord epoch timestamp this snowflake was generated
     */
    static constexpr int64_t c_get_timestamp(int64_t _snowflake) noexcept
    {
        return (_snowflake & _timestampMask) >> 22;
    };

    ///
    /**
     * @returns int64_t Unix timestamp this snowflake was generated
     */
    constexpr int64_t get_time() const noexcept
    {
        return get_timestamp() + _discordEpoch;
    };

    ///
    /**
     * @returns int64_t Unix timestamp this snowflake was generated
     */
    static constexpr int64_t c_get_time(int64_t _snowflake) noexcept
    {
        return c_get_timestamp(_snowflake) + _discordEpoch;
    };

private:
    uint64_t _id;
    static constexpr uint64_t _countMask = 0x0000000000000FFFL;
    static constexpr uint64_t _processMask = 0x000000000001F000L;
    static constexpr uint64_t _workerMask = 0x00000000003E0000L;
    static constexpr uint64_t _timestampMask = 0xFFFFFFFFFFC00000L;
    static constexpr uint64_t _discordEpoch = 1420070400000;
};

/// \cond TEMPLATES
AEGIS_DECL void from_json(const nlohmann::json& j, snowflake& s);
AEGIS_DECL void to_json(nlohmann::json& j, const snowflake& s);
/// \endcond

}

/// \cond TEMPLATES
namespace std
{

template <>
struct hash<aegis::snowflake>
{
    std::size_t operator()(const aegis::snowflake& k) const
    {
        return hash<int64_t>()(k.get());
    }
};

}
/// \endcond

#if defined(AEGIS_HEADER_ONLY)
#include "aegis/impl/snowflake.cpp"
#endif
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_APP_HPP
#define INCLUDE_AL_APP_HPP
/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

	File description:
	Base class for common applications

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com
*/

#include <math.h>
#include <string>
#include <vector>
#include "allocore/al_Allocore.hpp"
#include "alloutil/al_ControlNav.hpp"

namespace al{

/// Viewpoint within a scene

/// A viewpoint is an aggregation of a viewport (screen region), a pose
/// (3D position and orientation), and a lens.
class Viewpoint{
public:

	Viewpoint(const Pose& transform = Pose::identity())
	:	mViewport(0,0,0,0),
		mParentTransform(NULL),
		mAnchorX(0), mAnchorY(0), mStretchX(1), mStretchY(1),
		mLens(NULL), mClearColor(NULL)
	{}

	float anchorX() const { return mAnchorX; }
	float anchorY() const { return mAnchorY; }
	float stretchX() const { return mStretchX; }
	float stretchY() const { return mStretchY; }

	/// Set anchoring factors relative to bottom-left corner of window

	/// @param[in] ax	anchor factor relative to left edge of window, in [0,1]
	/// @param[in] ay	anchor factor relative to bottom edge of window, in [0,1]
	Viewpoint& anchor(float ax, float ay){
		mAnchorX=ax; mAnchorY=ay; return *this;
	}

	/// Set stretch factors relative to bottom-left corner of window

	/// @param[in] sx	stretch factor relative to left edge of window, in [0,1]
	/// @param[in] sy	stretch factor relative to bottom edge of window, in [0,1]
	Viewpoint& stretch(float sx, float sy){
		mStretchX=sx; mStretchY=sy; return *this;
	}

	bool hasLens() const { return NULL != mLens; }
	bool hasClearColor() const { return NULL != mClearColor; }

	const Lens& lens() const { return *mLens; }
	Viewpoint& lens(Lens& v){ mLens=&v; return *this; }

	const Color& clearColor() const { return *mClearColor; }
	Viewpoint& clearColor(Color& v){ mClearColor=&v; return *this; }

	const Pose* parentTransform() const { return mParentTransform; }
	Viewpoint& parentTransform(Pose& v){ mParentTransform =&v; return *this; }
	Viewpoint& parentTransform(Pose* v){ mParentTransform = v; return *this; }

	const Pose& transform() const { return mTransform; }
	Pose& transform(){ return mTransform; }
	Viewpoint& transform(const Pose& v){ mTransform=v; return *this; }

	Pose worldTransform() const { return mParentTransform ? (*mParentTransform) * transform() : transform(); }

	const Viewport& viewport() const { return mViewport; }
	Viewport& viewport(){ return mViewport; }

protected:
	Viewport mViewport;				// screen display region
	Pose * mParentTransform;		// parent transform, 0 if none
	Pose mTransform;				// local transform
	float mAnchorX, mAnchorY;		// viewport anchor factors relative to parent window
	float mStretchX, mStretchY;		// viewport stretch factors relative to parent window
	Lens * mLens;					// if not set, will be set to scene's default lens
	Color * mClearColor;
};

/// A window with one or more Viewpoints
class ViewpointWindow : public Window {
public:
	typedef std::vector<Viewpoint *> Viewpoints;

	///
	ViewpointWindow(){
		init();
	}

	/// @param[in] dims		window dimensions
	/// @param[in] title	window title
	/// @param[in] fps		frames/second
	/// @param[in] mode		window display mode
	ViewpointWindow(
		const Dim& dims,
		const std::string title="",
		double fps=40,
		DisplayMode mode = DEFAULT_BUF
	){
		init();
		create(dims, title, fps, mode);
	}

	/// Get the list of viewpoints
	Viewpoints& viewpoints(){ return mViewpoints; }
	const Viewpoints& viewpoints() const { return mViewpoints; }

	/// Add a new viewpoint to the window
	ViewpointWindow& add(Viewpoint& v){ mViewpoints.push_back(&v); return *this; }

protected:
	Viewpoints mViewpoints;

	virtual bool onResize(int dw, int dh);

private:
	StandardWindowKeyControls mStandardKeyControls;
	void init(){
		append(mStandardKeyControls);
	}
};

/// Application helper class
class App {
//: public WindowEventHandler, public InputEventHandler {
public:

	typedef std::vector<Listener *>			Listeners;
	typedef std::vector<ViewpointWindow *>	Windows;

	App();
	virtual ~App();

	/// Initialize audio

	/// @param[in] sampleRate		Sampling rate.  Unsupported values will use default rate of device.
	/// @param[in] blockSize		Number of sample frames to process per callback
	/// @param[in] outputChannels	Number of output channels to open
	/// @param[in] inputChannels	Number of input channels to open
	void initAudio(
		double audioRate=44100, int blockSize=128,
		int outputChannels=-1, int inputChannels=-1
	);

	/// Initialize a new window

	/// @param[in] dims				Window dimensions
	/// @param[in] title			Window title
	/// @param[in] fps				Frames/second
	/// @param[in] mode				Window display mode
	ViewpointWindow * initWindow(
		const Window::Dim& dims = Window::Dim(800,600),
		const std::string title="",
		double fps=40,
		Window::DisplayMode mode = Window::DEFAULT_BUF,
		int flags=0
	);

	/// Start rendering; begins audio and drawing callbacks
	void start();

	/// Sound generation callback

	/// Sound can either be written directly to the audio output channels
	/// or to the sound source's internal buffer which is rendered later by the
	/// spatial audio decoder.
	virtual void onSound(AudioIOData& io){}

	/// Animation (model update) callback
	virtual void onAnimate(double dt){}

	/// Drawing callback (in world coordinates)

	/// This will be called from the main graphics renderer. Since it may be
	/// called multiple times, no state updates should be made in it.
	virtual void onDraw(Graphics& g, const Viewpoint& v){}

	/// Called when a keyboard key is pressed
	virtual void onKeyDown(const ViewpointWindow& w, const Keyboard& k){}

	/// Called when a keyboard key is released
	virtual void onKeyUp(const ViewpointWindow& w, const Keyboard& k){}

	/// Called when a mouse button is pressed
	virtual void onMouseDown(const ViewpointWindow& w, const Mouse& m){}

	/// Called when a mouse button is released
	virtual void onMouseUp(const ViewpointWindow& w, const Mouse& m){}

	/// Called when the mouse moves while a button is down
	virtual void onMouseDrag(const ViewpointWindow& w, const Mouse& m){}

	/// Called when the mouse moves
	virtual void onMouseMove(const ViewpointWindow& w, const Mouse& m){}

	/// Called upon creation of a window
	virtual void onCreate(const ViewpointWindow& win){}

	/// Called upon destruction of a window
	virtual void onDestroy(const ViewpointWindow& win){}

	/// Called upon resize of a window
	virtual void onResize(const ViewpointWindow& win, int dw, int dh){}

	const AudioIO&		audioIO() const { return mAudioIO; }
	AudioIO&			audioIO(){ return mAudioIO; }

	//const AudioScene&	audioScene() const { return mAudioScene; }
	//AudioScene&			audioScene(){ return mAudioScene; }

	const Lens&			lens() const { return mLens; }
	Lens&				lens(){ return mLens; }

	const Graphics&		graphics() const { return mGraphics; }
	Graphics&			graphics(){ return mGraphics; }

	const std::string&	name() const { return mName; }
	App&				name(const std::string& v){ mName=v; return *this; }

	const Nav&			nav() const { return mNav; }
	Nav&				nav(){ return mNav; }

	const Nav&			navDraw() const { return mNavDraw; }
	Nav&				navDraw(){ return mNavDraw; }

	const NavInputControl& navControl() const { return mNavControl; }
	NavInputControl&	navControl(){ return mNavControl; }

	osc::Recv&			oscRecv(){ return mOSCRecv; }
	osc::Send&			oscSend(){ return mOSCSend; }

	const Stereographic& stereo() const { return mStereo; }
	Stereographic&		stereo(){ return mStereo; }

	const Windows&		windows() const { return mWindows; }
	Windows&			windows(){ return mWindows; }

	const void *		clockAnimate() const { return mClockAnimate; }
	App&				clockAnimate(void * v){ mClockAnimate=v; return *this; }

	const void *		clockNav() const { return mClockNav; }
	App&				clockNav(void * v){ mClockNav=v; return *this; }

	/// Add a window to the world

	/// @param[in] win			The window to add
	///
	App& add(ViewpointWindow& win);

	void sendHandshake(){
		oscSend().send("/handshake", name(), oscRecv().port());
	}

	void sendDisconnect(){
		oscSend().send("/disconnectApplication", name());
	}

	/// Returns true if using audio
	bool usingAudio() const;

private:

	typedef std::vector<Viewpoint *> Viewpoints;

	Viewpoints mFacViewpoints;
	Windows mFacWindows;

	// graphics
	Windows mWindows;
	Lens mLens;
	Stereographic mStereo;
	Graphics mGraphics;

	// sound
	AudioIO mAudioIO;
	//AudioScene mAudioScene;
	//Listeners mListeners;

	// spatial
	Nav mNav;
	Nav mNavDraw;	// this version remains invariant throughout all drawing

	// control
	NavInputControl mNavControl;
	osc::Recv mOSCRecv;
	osc::Send mOSCSend;

	std::string mName;
	void * mClockAnimate;
	void * mClockNav;

	// attached to each ViewpointWindow
	struct SceneWindowHandler : public WindowEventHandler{
		ViewpointWindow& win;
		App& app;

		SceneWindowHandler(ViewpointWindow& w, App& a): win(w), app(a){}

		virtual bool onCreate(){
			app.onCreate(win);
			return true;
		}

		virtual bool onDestroy(){
			app.onDestroy(win);
			return true;
		}

		virtual bool onResize(int dw, int dh){
			app.onResize(win, dw,dh);
			return true;
		}

		virtual bool onFrame();
	};

	struct SceneInputHandler : public InputEventHandler{
		ViewpointWindow& win;
		App& app;

		SceneInputHandler(ViewpointWindow& w, App& a): win(w), app(a){}

		virtual bool onKeyDown(const Keyboard& k){
			app.onKeyDown(win, k);
			switch(k.key()){
				case Keyboard::TAB: app.stereo().stereo(!app.stereo().stereo()); return false;
				default:;
			}
			return true;
		}
		virtual bool onKeyUp(const Keyboard& k){ app.onKeyUp(win,k); return true;}
		virtual bool onMouseDown(const Mouse& m){ app.onMouseDown(win,m); return true;}
		virtual bool onMouseUp(const Mouse& m){ app.onMouseUp(win,m); return true;}
		virtual bool onMouseDrag(const Mouse& m){ app.onMouseDrag(win,m); return true;}
		virtual bool onMouseMove(const Mouse& m){ app.onMouseMove(win,m); return true;}
	};

//	struct SceneInputHandler : public StandardWindowKeyControls{
//		SceneInputHandler(App& a): app(a){}
//
//		virtual bool onKeyDown(const Keyboard& k){
//			if(!StandardWindowKeyControls::onKeyDown(k)) return false;
//			switch(k.key()){
//				case Keyboard::TAB: app.stereo().stereo(!app.stereo().stereo()); return false;
//				default:;
//			}
//			return true;
//		}
//
//		App& app;
//	};

};

} // al::
#endif
<commit_msg>comments<commit_after>#ifndef INCLUDE_AL_APP_HPP
#define INCLUDE_AL_APP_HPP
/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

	File description:
	Base class for common applications

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com
*/

#include <math.h>
#include <string>
#include <vector>
#include "allocore/al_Allocore.hpp"
#include "alloutil/al_ControlNav.hpp"

namespace al{

/// Viewpoint within a scene

/// A viewpoint is an aggregation of a viewport (screen region), a pose
/// (3D position and orientation), and a lens.
class Viewpoint{
public:

	Viewpoint(const Pose& transform = Pose::identity())
	:	mViewport(0,0,0,0),
		mParentTransform(NULL),
		mAnchorX(0), mAnchorY(0), mStretchX(1), mStretchY(1),
		mLens(NULL), mClearColor(NULL)
	{}

	float anchorX() const { return mAnchorX; }
	float anchorY() const { return mAnchorY; }
	float stretchX() const { return mStretchX; }
	float stretchY() const { return mStretchY; }

	/// Set anchoring factors relative to bottom-left corner of window

	/// @param[in] ax	anchor factor relative to left edge of window, in [0,1]
	/// @param[in] ay	anchor factor relative to bottom edge of window, in [0,1]
	Viewpoint& anchor(float ax, float ay){
		mAnchorX=ax; mAnchorY=ay; return *this;
	}

	/// Set stretch factors relative to bottom-left corner of window

	/// @param[in] sx	stretch factor relative to left edge of window, in [0,1]
	/// @param[in] sy	stretch factor relative to bottom edge of window, in [0,1]
	Viewpoint& stretch(float sx, float sy){
		mStretchX=sx; mStretchY=sy; return *this;
	}

	bool hasLens() const { return NULL != mLens; }
	bool hasClearColor() const { return NULL != mClearColor; }

	const Lens& lens() const { return *mLens; }
	Viewpoint& lens(Lens& v){ mLens=&v; return *this; }

	const Color& clearColor() const { return *mClearColor; }
	Viewpoint& clearColor(Color& v){ mClearColor=&v; return *this; }

	const Pose* parentTransform() const { return mParentTransform; }
	Viewpoint& parentTransform(Pose& v){ mParentTransform =&v; return *this; }
	Viewpoint& parentTransform(Pose* v){ mParentTransform = v; return *this; }

	const Pose& transform() const { return mTransform; }
	Pose& transform(){ return mTransform; }
	Viewpoint& transform(const Pose& v){ mTransform=v; return *this; }

	Pose worldTransform() const { return mParentTransform ? (*mParentTransform) * transform() : transform(); }

	const Viewport& viewport() const { return mViewport; }
	Viewport& viewport(){ return mViewport; }

protected:
	Viewport mViewport;				// screen display region
	Pose * mParentTransform;		// parent transform, 0 if none
	Pose mTransform;				// local transform
	float mAnchorX, mAnchorY;		// viewport anchor factors relative to parent window
	float mStretchX, mStretchY;		// viewport stretch factors relative to parent window
	Lens * mLens;					// if not set, will be set to scene's default lens
	Color * mClearColor;
};

/// A window with one or more Viewpoints
class ViewpointWindow : public Window {
public:
	typedef std::vector<Viewpoint *> Viewpoints;

	///
	ViewpointWindow(){
		init();
	}

	/// @param[in] dims		window dimensions
	/// @param[in] title	window title
	/// @param[in] fps		frames/second
	/// @param[in] mode		window display mode
	ViewpointWindow(
		const Dim& dims,
		const std::string title="",
		double fps=40,
		DisplayMode mode = DEFAULT_BUF
	){
		init();
		create(dims, title, fps, mode);
	}

	/// Get the list of viewpoints
	Viewpoints& viewpoints(){ return mViewpoints; }
	const Viewpoints& viewpoints() const { return mViewpoints; }

	/// Add a new viewpoint to the window
	ViewpointWindow& add(Viewpoint& v){ mViewpoints.push_back(&v); return *this; }

protected:
	Viewpoints mViewpoints;

	virtual bool onResize(int dw, int dh);

private:
	StandardWindowKeyControls mStandardKeyControls;
	void init(){
		append(mStandardKeyControls);
	}
};

/// Application helper class
class App {
//: public WindowEventHandler, public InputEventHandler {
public:

	typedef std::vector<Listener *>			Listeners;
	typedef std::vector<ViewpointWindow *>	Windows;

	App();
	virtual ~App();

	/// Initialize audio

	/// @param[in] sampleRate		Sampling rate.  Unsupported values will use default rate of device.
	/// @param[in] blockSize		Number of sample frames to process per callback
	/// @param[in] outputChannels	Number of output channels to open or -1 for all
	/// @param[in] inputChannels	Number of input channels to open or -1 for all
	void initAudio(
		double audioRate=44100, int blockSize=128,
		int outputChannels=-1, int inputChannels=-1
	);

	/// Initialize a new window

	/// @param[in] dims				Window dimensions
	/// @param[in] title			Window title
	/// @param[in] fps				Frames/second
	/// @param[in] mode				Window display mode
	ViewpointWindow * initWindow(
		const Window::Dim& dims = Window::Dim(800,600),
		const std::string title="",
		double fps=40,
		Window::DisplayMode mode = Window::DEFAULT_BUF,
		int flags=0
	);

	/// Start rendering; begins audio and drawing callbacks
	void start();

	/// Sound generation callback

	/// Sound can either be written directly to the audio output channels
	/// or to the sound source's internal buffer which is rendered later by the
	/// spatial audio decoder.
	virtual void onSound(AudioIOData& io){}

	/// Animation (model update) callback
	virtual void onAnimate(double dt){}

	/// Drawing callback (in world coordinates)

	/// This will be called from the main graphics renderer. Since it may be
	/// called multiple times, no state updates should be made in it.
	virtual void onDraw(Graphics& g, const Viewpoint& v){}

	/// Called when a keyboard key is pressed
	virtual void onKeyDown(const ViewpointWindow& w, const Keyboard& k){}

	/// Called when a keyboard key is released
	virtual void onKeyUp(const ViewpointWindow& w, const Keyboard& k){}

	/// Called when a mouse button is pressed
	virtual void onMouseDown(const ViewpointWindow& w, const Mouse& m){}

	/// Called when a mouse button is released
	virtual void onMouseUp(const ViewpointWindow& w, const Mouse& m){}

	/// Called when the mouse moves while a button is down
	virtual void onMouseDrag(const ViewpointWindow& w, const Mouse& m){}

	/// Called when the mouse moves
	virtual void onMouseMove(const ViewpointWindow& w, const Mouse& m){}

	/// Called upon creation of a window
	virtual void onCreate(const ViewpointWindow& win){}

	/// Called upon destruction of a window
	virtual void onDestroy(const ViewpointWindow& win){}

	/// Called upon resize of a window
	virtual void onResize(const ViewpointWindow& win, int dw, int dh){}

	const AudioIO&		audioIO() const { return mAudioIO; }
	AudioIO&			audioIO(){ return mAudioIO; }

	//const AudioScene&	audioScene() const { return mAudioScene; }
	//AudioScene&			audioScene(){ return mAudioScene; }

	const Lens&			lens() const { return mLens; }
	Lens&				lens(){ return mLens; }

	const Graphics&		graphics() const { return mGraphics; }
	Graphics&			graphics(){ return mGraphics; }

	const std::string&	name() const { return mName; }
	App&				name(const std::string& v){ mName=v; return *this; }

	const Nav&			nav() const { return mNav; }
	Nav&				nav(){ return mNav; }

	const Nav&			navDraw() const { return mNavDraw; }
	Nav&				navDraw(){ return mNavDraw; }

	const NavInputControl& navControl() const { return mNavControl; }
	NavInputControl&	navControl(){ return mNavControl; }

	osc::Recv&			oscRecv(){ return mOSCRecv; }
	osc::Send&			oscSend(){ return mOSCSend; }

	const Stereographic& stereo() const { return mStereo; }
	Stereographic&		stereo(){ return mStereo; }

	const Windows&		windows() const { return mWindows; }
	Windows&			windows(){ return mWindows; }

	const void *		clockAnimate() const { return mClockAnimate; }
	App&				clockAnimate(void * v){ mClockAnimate=v; return *this; }

	const void *		clockNav() const { return mClockNav; }
	App&				clockNav(void * v){ mClockNav=v; return *this; }

	/// Add a window to the world

	/// @param[in] win			The window to add
	///
	App& add(ViewpointWindow& win);

	void sendHandshake(){
		oscSend().send("/handshake", name(), oscRecv().port());
	}

	void sendDisconnect(){
		oscSend().send("/disconnectApplication", name());
	}

	/// Returns true if using audio
	bool usingAudio() const;

private:

	typedef std::vector<Viewpoint *> Viewpoints;

	Viewpoints mFacViewpoints;
	Windows mFacWindows;

	// graphics
	Windows mWindows;
	Lens mLens;
	Stereographic mStereo;
	Graphics mGraphics;

	// sound
	AudioIO mAudioIO;
	//AudioScene mAudioScene;
	//Listeners mListeners;

	// spatial
	Nav mNav;
	Nav mNavDraw;	// this version remains invariant throughout all drawing

	// control
	NavInputControl mNavControl;
	osc::Recv mOSCRecv;
	osc::Send mOSCSend;

	std::string mName;
	void * mClockAnimate;
	void * mClockNav;

	// attached to each ViewpointWindow
	struct SceneWindowHandler : public WindowEventHandler{
		ViewpointWindow& win;
		App& app;

		SceneWindowHandler(ViewpointWindow& w, App& a): win(w), app(a){}

		virtual bool onCreate(){
			app.onCreate(win);
			return true;
		}

		virtual bool onDestroy(){
			app.onDestroy(win);
			return true;
		}

		virtual bool onResize(int dw, int dh){
			app.onResize(win, dw,dh);
			return true;
		}

		virtual bool onFrame();
	};

	struct SceneInputHandler : public InputEventHandler{
		ViewpointWindow& win;
		App& app;

		SceneInputHandler(ViewpointWindow& w, App& a): win(w), app(a){}

		virtual bool onKeyDown(const Keyboard& k){
			app.onKeyDown(win, k);
			switch(k.key()){
				case Keyboard::TAB: app.stereo().stereo(!app.stereo().stereo()); return false;
				default:;
			}
			return true;
		}
		virtual bool onKeyUp(const Keyboard& k){ app.onKeyUp(win,k); return true;}
		virtual bool onMouseDown(const Mouse& m){ app.onMouseDown(win,m); return true;}
		virtual bool onMouseUp(const Mouse& m){ app.onMouseUp(win,m); return true;}
		virtual bool onMouseDrag(const Mouse& m){ app.onMouseDrag(win,m); return true;}
		virtual bool onMouseMove(const Mouse& m){ app.onMouseMove(win,m); return true;}
	};

//	struct SceneInputHandler : public StandardWindowKeyControls{
//		SceneInputHandler(App& a): app(a){}
//
//		virtual bool onKeyDown(const Keyboard& k){
//			if(!StandardWindowKeyControls::onKeyDown(k)) return false;
//			switch(k.key()){
//				case Keyboard::TAB: app.stereo().stereo(!app.stereo().stereo()); return false;
//				default:;
//			}
//			return true;
//		}
//
//		App& app;
//	};

};

} // al::
#endif
<|endoftext|>


<commit_before>#ifndef UTILS_H_
#define UTILS_H_

#include <type_traits>
#include <functional>
#include <vector>
#include <cassert>

namespace evolve
{

    template<typename T>
    struct count_args;

    template<typename T, typename... U>
    struct count_args<std::function<T(U...)>>
    {
        static const unsigned int value = sizeof...(U);
    };

    template<unsigned int... ints> struct Ints{};

    template<typename intList, bool one>
    struct RangeHelper;

    template<unsigned int... ints>
    struct RangeHelper<Ints<ints...>, true>{
        typedef Ints<ints...> type;
    };

    template<unsigned int... ints, unsigned int head>
    struct RangeHelper<Ints<head, ints...>, false> :
        public RangeHelper<Ints<head-1, head, ints...>, head-1==0>{};

    template<unsigned int bound>
    struct Range : public RangeHelper<Ints<bound>, bound==0>{};

    template <typename T>
    struct unpack_caller
    {
    private:
        template <typename FuncType, unsigned int... I>
        static T call(FuncType f, const std::vector<T>& args, Ints<I...>){
            return f(args.at(I)...);
        }

    public:
        template <typename FuncType>
        static T eval(FuncType f, const std::vector<T>& args){
            assert(args.size() == count_args<FuncType>::value); // just to be sure
            return call(f, args, typename Range<count_args<FuncType>::value-1>::type{});
        }
    };

    template<typename>
    struct sfinae_true : std::true_type{};

    #define HAS_MEMBER(func, name)                                                      \
                                                                                \
        template<typename T>                                                                \
        static auto name ## _test(int) -> sfinae_true<decltype(std::declval<T>().func)>;    \
                                                                                \
        template<typename>                                                                  \
        static auto name ## _test(long) -> std::false_type;                                 \
                                                                                \
        template<typename T>                                                                \
        struct name : decltype(name ## _test<T>(0)){};

    HAS_MEMBER(operator[](0), has_indexing);

    HAS_MEMBER(push_back(std::declval<typename T::value_type>()), has_pushback);

    HAS_MEMBER(insert(std::declval<typename T::iterator>(),
                      std::declval<typename T::iterator>(),
                      std::declval<typename T::iterator>()), has_range_insert);

    HAS_MEMBER(insert(std::declval<typename T::iterator>(),
                      std::declval<typename T::value_type>()), has_location_insert);

}
#endif
<commit_msg>Performance improvements<commit_after>#ifndef UTILS_H_
#define UTILS_H_

#include <type_traits>
#include <functional>
#include <vector>
#include <cassert>

namespace evolve
{

    template<typename T>
    struct count_args;

    template<typename T, typename... U>
    struct count_args<std::function<T(U...)>>
    {
        static const unsigned int value = sizeof...(U);
    };

    template<unsigned int... ints> struct Ints{};

    template<typename intList, bool one>
    struct RangeHelper;

    template<unsigned int... ints>
    struct RangeHelper<Ints<ints...>, true>{
        typedef Ints<ints...> type;
    };

    template<unsigned int... ints, unsigned int head>
    struct RangeHelper<Ints<head, ints...>, false> :
        public RangeHelper<Ints<head-1, head, ints...>, head-1==0>{};

    template<unsigned int bound>
    struct Range : public RangeHelper<Ints<bound>, bound==0>{};

    template <typename T>
    struct unpack_caller
    {
    private:
        template <typename FuncType, typename U, unsigned int... I>
        static T call(FuncType f, const std::vector<U>& args, Ints<I...>){
            return f(args[I]->eval()...);
        }

    public:
        template <typename FuncType, typename U>
        static T eval(FuncType f, const std::vector<U>& args){
            assert(args.size() == count_args<FuncType>::value); // just to be sure
            return call(f, args, typename Range<count_args<FuncType>::value-1>::type{});
        }
    };

    template<typename>
    struct sfinae_true : std::true_type{};

    #define HAS_MEMBER(func, name)                                                      \
                                                                                \
        template<typename T>                                                                \
        static auto name ## _test(int) -> sfinae_true<decltype(std::declval<T>().func)>;    \
                                                                                \
        template<typename>                                                                  \
        static auto name ## _test(long) -> std::false_type;                                 \
                                                                                \
        template<typename T>                                                                \
        struct name : decltype(name ## _test<T>(0)){};

    HAS_MEMBER(operator[](0), has_indexing);

    HAS_MEMBER(push_back(std::declval<typename T::value_type>()), has_pushback);

    HAS_MEMBER(insert(std::declval<typename T::iterator>(),
                      std::declval<typename T::iterator>(),
                      std::declval<typename T::iterator>()), has_range_insert);

    HAS_MEMBER(insert(std::declval<typename T::iterator>(),
                      std::declval<typename T::value_type>()), has_location_insert);

}
#endif
<|endoftext|>


<commit_before>#ifndef DOORMAT_DOORMAT_HPP_
#define DOORMAT_DOORMAT_HPP_

#include "chain.hpp"
#include "configuration.hpp"
#include "http.hpp"
#include "io_service_pool.hpp"
#include "network.hpp"
#include "node_interface.hpp"
#include "server.hpp"
#include "service.hpp"
#include "stats.hpp"
#include "client.hpp"
#include "utils.hpp"
#include "errors.hpp"

#endif // DOORMAT_DOORMAT_HPP_
<commit_msg>removed not existent exported include<commit_after>#ifndef DOORMAT_DOORMAT_HPP_
#define DOORMAT_DOORMAT_HPP_

#include "chain.hpp"
#include "configuration.hpp"
#include "http.hpp"
#include "io_service_pool.hpp"
#include "node_interface.hpp"
#include "server.hpp"
#include "service.hpp"
#include "stats.hpp"
#include "client.hpp"
#include "utils.hpp"
#include "errors.hpp"

#endif // DOORMAT_DOORMAT_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright 2014-2018, Nicolas Mansard and Justin Carpentier, LAAS-CNRS
 *
 * This file is part of eigenpy.
 * eigenpy is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * eigenpy is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with eigenpy.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __eigenpy_details_hpp__
#define __eigenpy_details_hpp__

#include "eigenpy/fwd.hpp"

#include <numpy/arrayobject.h>
#include <iostream>

#include "eigenpy/eigenpy.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/map.hpp"

#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0)

namespace eigenpy
{
  template <typename SCALAR>  struct NumpyEquivalentType {};
  template <> struct NumpyEquivalentType<double>  { enum { type_code = NPY_DOUBLE };};
  template <> struct NumpyEquivalentType<int>     { enum { type_code = NPY_INT    };};
  template <> struct NumpyEquivalentType<long>     { enum { type_code = NPY_LONG    };};
  template <> struct NumpyEquivalentType<float>   { enum { type_code = NPY_FLOAT  };};

  template <typename SCALAR1, typename SCALAR2>
  struct FromTypeToType : public boost::false_type {};

  template <typename SCALAR>
  struct FromTypeToType<SCALAR,SCALAR> : public boost::true_type {};

  template <> struct FromTypeToType<int,long> : public boost::true_type {};
  template <> struct FromTypeToType<int,float> : public boost::true_type {};
  template <> struct FromTypeToType<int,double> : public boost::true_type {};

  template <> struct FromTypeToType<long,float> : public boost::true_type {};
  template <> struct FromTypeToType<long,double> : public boost::true_type {};

  template <> struct FromTypeToType<float,double> : public boost::true_type {};

  namespace bp = boost::python;

  struct PyMatrixType
  {

    static PyMatrixType & getInstance()
    {
      static PyMatrixType instance;
      return instance;
    }

    operator bp::object () { return pyMatrixType; }

    bp::object make(PyArrayObject* pyArray, bool copy = false)
    { return make((PyObject*)pyArray,copy); }
    bp::object make(PyObject* pyObj, bool copy = false)
    {
      bp::object m
      = pyMatrixType(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
      Py_INCREF(m.ptr());
      return m;
    }

  protected:
    PyMatrixType()
    {
      pyModule = bp::import("numpy");
      pyMatrixType = pyModule.attr("matrix");
    }

    bp::object pyMatrixType;
    bp::object pyModule;
  };

  template<typename MatType>
  struct EigenObjectAllocator
  {
    typedef MatType Type;
    typedef typename MatType::Scalar Scalar;

    static void allocate(PyArrayObject * pyArray, void * storage)
    {
      const int rows = (int)PyArray_DIMS(pyArray)[0];
      const int cols = (int)PyArray_DIMS(pyArray)[1];

      Type * mat_ptr = new(storage) Type(rows,cols);
      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
        *mat_ptr = MapNumpy<MatType,int>::map(pyArray).template cast<Scalar>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
        *mat_ptr = MapNumpy<MatType,long>::map(pyArray).template cast<Scalar>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
        *mat_ptr = MapNumpy<MatType,float>::map(pyArray).template cast<Scalar>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
        *mat_ptr = MapNumpy<MatType,double>::map(pyArray).template cast<Scalar>();
    }

    static void convert(Type const & mat , PyArrayObject * pyArray)
    {
      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
        MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
        MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
        MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
        MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
    }
  };

#if EIGEN_VERSION_AT_LEAST(3,2,0)
  template<typename MatType>
  struct EigenObjectAllocator< eigenpy::Ref<MatType> >
  {
    typedef eigenpy::Ref<MatType> Type;
    typedef typename MatType::Scalar Scalar;

    static void allocate(PyArrayObject * pyArray, void * storage)
    {
      typename MapNumpy<MatType,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray);
      new(storage) Type(numpyMap);
    }

    static void convert(Type const & mat , PyArrayObject * pyArray)
    {
      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
        MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
        MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
        MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
        MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
    }
  };
#endif

  /* --- TO PYTHON -------------------------------------------------------------- */
  template<typename MatType>
  struct EigenToPy
  {
    static PyObject* convert(MatType const& mat)
    {
      typedef typename MatType::Scalar T;
      assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
	      && "Matrix range larger than int ... should never happen." );
      const int R  = (int)mat.rows(), C = (int)mat.cols();

      npy_intp shape[2] = { R,C };
      PyArrayObject* pyArray = (PyArrayObject*)
      PyArray_SimpleNew(2, shape, NumpyEquivalentType<T>::type_code);

      EigenObjectAllocator<MatType>::convert(mat,pyArray);

      return PyMatrixType::getInstance().make(pyArray).ptr();
    }
  };

  /* --- FROM PYTHON ------------------------------------------------------------ */

  template<typename MatType>
  struct EigenFromPy
  {
    // Determine if obj_ptr can be converted in a Eigenvec
    static void* convertible(PyArrayObject* obj_ptr)
    {
      if (!PyArray_Check(obj_ptr))
      {
#ifndef NDEBUG
        std::cerr << "The python object is not a numpy array." << std::endl;
#endif
        return 0;
      }
      if(MatType::IsVectorAtCompileTime)
      {
        // Special care of scalar matrix of dimension 1x1.
        if(PyArray_DIMS(obj_ptr)[0] == 1 && PyArray_DIMS(obj_ptr)[1] == 1)
          return obj_ptr;

        if(PyArray_DIMS(obj_ptr)[0] > 1 && PyArray_DIMS(obj_ptr)[1] > 1)
        {
#ifndef NDEBUG
          std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
#endif
          return 0;
        }

        if(((PyArray_DIMS(obj_ptr)[0] == 1) && (MatType::ColsAtCompileTime == 1))
           || ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
        {
#ifndef NDEBUG
          if(MatType::ColsAtCompileTime == 1)
            std::cerr << "The object is not a column vector" << std::endl;
          else
            std::cerr << "The object is not a row vector" << std::endl;
#endif
          return 0;
        }
      }

      if (PyArray_NDIM(obj_ptr) != 2)
      {
        if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
        {
#ifndef NDEBUG
          std::cerr << "The number of dimension of the object is not correct." << std::endl;
#endif
          return 0;
        }
      }

      // Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType
      if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_INT)
      {
        if(not FromTypeToType<int,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar type (int) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_LONG)
      {
        if(not FromTypeToType<long,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar type (long) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_FLOAT)
      {
        if(not FromTypeToType<float,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar type (float) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_DOUBLE)
      {
        if(not FromTypeToType<double,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar (double) type cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision." << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
          != NumpyEquivalentType<typename MatType::Scalar>::type_code)
      {
#ifndef NDEBUG
        std::cerr << "The internal type as no Eigen equivalent." << std::endl;
#endif

        return 0;
      }

#ifdef NPY_1_8_API_VERSION
      if (!(PyArray_FLAGS(obj_ptr)))
#else
        if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
#endif
        {
#ifndef NDEBUG
          std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
#endif
          return 0;
        }

      return obj_ptr;
    }

    // Convert obj_ptr into a Eigenvec
    static void construct(PyObject* pyObj,
                          bp::converter::rvalue_from_python_stage1_data* memory)
    {
      using namespace Eigen;

      PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
      assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));

      void* storage = ((bp::converter::rvalue_from_python_storage<MatType>*)
                       ((void*)memory))->storage.bytes;

      EigenObjectAllocator<MatType>::allocate(pyArray,storage);

      memory->convertible = storage;
    }
  };

#define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } }

  template<typename MatType,typename EigenEquivalentType>
  void enableEigenPySpecific()
  {
    enableEigenPySpecific<MatType>();
  }

  template<typename MatType>
  struct EigenFromPyConverter
  {
    static void registration()
    {
      bp::converter::registry::push_back
      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
       &EigenFromPy<MatType>::construct,bp::type_id<MatType>());

      // Add also conversion to Eigen::MatrixBase<MatType>
      bp::converter::registry::push_back
      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
       &EigenFromPy<MatType>::construct,bp::type_id< Eigen::MatrixBase<MatType> >());
    }
  };

  template<typename MatType>
  struct EigenFromPyConverter< eigenpy::Ref<MatType> >
  {
    static void registration()
    {
      bp::converter::registry::push_back
      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
       &EigenFromPy<MatType>::construct,bp::type_id<MatType>());
    }
  };

  template<typename MatType>
  void enableEigenPySpecific()
  {
    numpy_import_array();
    if(check_registration<MatType>()) return;

    bp::to_python_converter<MatType,EigenToPy<MatType> >();
    EigenFromPyConverter<MatType>::registration();

  }

} // namespace eigenpy

#endif // ifndef __eigenpy_details_hpp__
<commit_msg>[Conversion] Handle correctly the case Eigen::Ref<commit_after>/*
 * Copyright 2014-2018, Nicolas Mansard and Justin Carpentier, LAAS-CNRS
 *
 * This file is part of eigenpy.
 * eigenpy is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * eigenpy is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with eigenpy.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __eigenpy_details_hpp__
#define __eigenpy_details_hpp__

#include "eigenpy/fwd.hpp"

#include <numpy/arrayobject.h>
#include <iostream>

#include "eigenpy/eigenpy.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/map.hpp"

#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0)

namespace eigenpy
{
  template <typename SCALAR>  struct NumpyEquivalentType {};
  template <> struct NumpyEquivalentType<double>  { enum { type_code = NPY_DOUBLE };};
  template <> struct NumpyEquivalentType<int>     { enum { type_code = NPY_INT    };};
  template <> struct NumpyEquivalentType<long>     { enum { type_code = NPY_LONG    };};
  template <> struct NumpyEquivalentType<float>   { enum { type_code = NPY_FLOAT  };};

  template <typename SCALAR1, typename SCALAR2>
  struct FromTypeToType : public boost::false_type {};

  template <typename SCALAR>
  struct FromTypeToType<SCALAR,SCALAR> : public boost::true_type {};

  template <> struct FromTypeToType<int,long> : public boost::true_type {};
  template <> struct FromTypeToType<int,float> : public boost::true_type {};
  template <> struct FromTypeToType<int,double> : public boost::true_type {};

  template <> struct FromTypeToType<long,float> : public boost::true_type {};
  template <> struct FromTypeToType<long,double> : public boost::true_type {};

  template <> struct FromTypeToType<float,double> : public boost::true_type {};

  namespace bp = boost::python;

  struct PyMatrixType
  {

    static PyMatrixType & getInstance()
    {
      static PyMatrixType instance;
      return instance;
    }

    operator bp::object () { return pyMatrixType; }

    bp::object make(PyArrayObject* pyArray, bool copy = false)
    { return make((PyObject*)pyArray,copy); }
    bp::object make(PyObject* pyObj, bool copy = false)
    {
      bp::object m
      = pyMatrixType(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
      Py_INCREF(m.ptr());
      return m;
    }

  protected:
    PyMatrixType()
    {
      pyModule = bp::import("numpy");
      pyMatrixType = pyModule.attr("matrix");
    }

    bp::object pyMatrixType;
    bp::object pyModule;
  };

  template<typename MatType>
  struct EigenObjectAllocator
  {
    typedef MatType Type;
    typedef typename MatType::Scalar Scalar;

    static void allocate(PyArrayObject * pyArray, void * storage)
    {
      const int rows = (int)PyArray_DIMS(pyArray)[0];
      const int cols = (int)PyArray_DIMS(pyArray)[1];

      Type * mat_ptr = new(storage) Type(rows,cols);
      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
        *mat_ptr = MapNumpy<MatType,int>::map(pyArray).template cast<Scalar>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
        *mat_ptr = MapNumpy<MatType,long>::map(pyArray).template cast<Scalar>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
        *mat_ptr = MapNumpy<MatType,float>::map(pyArray).template cast<Scalar>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
        *mat_ptr = MapNumpy<MatType,double>::map(pyArray).template cast<Scalar>();
    }

    static void convert(Type const & mat , PyArrayObject * pyArray)
    {
      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
        MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
        MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
        MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
        MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
    }
  };

#if EIGEN_VERSION_AT_LEAST(3,2,0)
  template<typename MatType>
  struct EigenObjectAllocator< eigenpy::Ref<MatType> >
  {
    typedef eigenpy::Ref<MatType> Type;
    typedef typename MatType::Scalar Scalar;

    static void allocate(PyArrayObject * pyArray, void * storage)
    {
      typename MapNumpy<MatType,Scalar>::EigenMap numpyMap = MapNumpy<MatType,Scalar>::map(pyArray);
      new(storage) Type(numpyMap);
    }

    static void convert(Type const & mat , PyArrayObject * pyArray)
    {
      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
        MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
        MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
        MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();

      if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
        MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
    }
  };
#endif

  /* --- TO PYTHON -------------------------------------------------------------- */
  template<typename MatType>
  struct EigenToPy
  {
    static PyObject* convert(MatType const& mat)
    {
      typedef typename MatType::Scalar T;
      assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
	      && "Matrix range larger than int ... should never happen." );
      const int R  = (int)mat.rows(), C = (int)mat.cols();

      npy_intp shape[2] = { R,C };
      PyArrayObject* pyArray = (PyArrayObject*)
      PyArray_SimpleNew(2, shape, NumpyEquivalentType<T>::type_code);

      EigenObjectAllocator<MatType>::convert(mat,pyArray);

      return PyMatrixType::getInstance().make(pyArray).ptr();
    }
  };

  /* --- FROM PYTHON ------------------------------------------------------------ */

  template<typename MatType>
  struct EigenFromPy
  {
    // Determine if obj_ptr can be converted in a Eigenvec
    static void* convertible(PyArrayObject* obj_ptr)
    {
      if (!PyArray_Check(obj_ptr))
      {
#ifndef NDEBUG
        std::cerr << "The python object is not a numpy array." << std::endl;
#endif
        return 0;
      }
      if(MatType::IsVectorAtCompileTime)
      {
        // Special care of scalar matrix of dimension 1x1.
        if(PyArray_DIMS(obj_ptr)[0] == 1 && PyArray_DIMS(obj_ptr)[1] == 1)
          return obj_ptr;

        if(PyArray_DIMS(obj_ptr)[0] > 1 && PyArray_DIMS(obj_ptr)[1] > 1)
        {
#ifndef NDEBUG
          std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
#endif
          return 0;
        }

        if(((PyArray_DIMS(obj_ptr)[0] == 1) && (MatType::ColsAtCompileTime == 1))
           || ((PyArray_DIMS(obj_ptr)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
        {
#ifndef NDEBUG
          if(MatType::ColsAtCompileTime == 1)
            std::cerr << "The object is not a column vector" << std::endl;
          else
            std::cerr << "The object is not a row vector" << std::endl;
#endif
          return 0;
        }
      }

      if (PyArray_NDIM(obj_ptr) != 2)
      {
        if ( (PyArray_NDIM(obj_ptr) !=1) || (! MatType::IsVectorAtCompileTime) )
        {
#ifndef NDEBUG
          std::cerr << "The number of dimension of the object is not correct." << std::endl;
#endif
          return 0;
        }
      }

      // Check if the Scalar type of the obj_ptr is compatible with the Scalar type of MatType
      if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_INT)
      {
        if(not FromTypeToType<int,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar type (int) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_LONG)
      {
        if(not FromTypeToType<long,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar type (long) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_FLOAT)
      {
        if(not FromTypeToType<float,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar type (float) cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision" << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0)) == NPY_DOUBLE)
      {
        if(not FromTypeToType<double,typename MatType::Scalar>::value)
        {
#ifndef NDEBUG
          std::cerr << "The Python matrix scalar (double) type cannot be converted into the scalar type of the Eigen matrix. Loss of arithmetic precision." << std::endl;
#endif
          return 0;
        }
      }
      else if ((PyArray_ObjectType(reinterpret_cast<PyObject *>(obj_ptr), 0))
          != NumpyEquivalentType<typename MatType::Scalar>::type_code)
      {
#ifndef NDEBUG
        std::cerr << "The internal type as no Eigen equivalent." << std::endl;
#endif

        return 0;
      }

#ifdef NPY_1_8_API_VERSION
      if (!(PyArray_FLAGS(obj_ptr)))
#else
        if (!(PyArray_FLAGS(obj_ptr) & NPY_ALIGNED))
#endif
        {
#ifndef NDEBUG
          std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
#endif
          return 0;
        }

      return obj_ptr;
    }

    // Convert obj_ptr into a Eigenvec
    static void construct(PyObject* pyObj,
                          bp::converter::rvalue_from_python_stage1_data* memory)
    {
      using namespace Eigen;

      PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
      assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));

      void* storage = ((bp::converter::rvalue_from_python_storage<MatType>*)
                       ((void*)memory))->storage.bytes;

      EigenObjectAllocator<MatType>::allocate(pyArray,storage);

      memory->convertible = storage;
    }
  };

#define numpy_import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } }

  template<typename MatType,typename EigenEquivalentType>
  void enableEigenPySpecific()
  {
    enableEigenPySpecific<MatType>();
  }

  template<typename MatType>
  struct EigenFromPyConverter
  {
    static void registration()
    {
      bp::converter::registry::push_back
      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
       &EigenFromPy<MatType>::construct,bp::type_id<MatType>());

      // Add also conversion to Eigen::MatrixBase<MatType>
      bp::converter::registry::push_back
      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
       &EigenFromPy<MatType>::construct,bp::type_id< Eigen::MatrixBase<MatType> >());
    }
  };

#if EIGEN_VERSION_AT_LEAST(3,2,0)
  /// Template specialization for Eigen::Ref
  template<typename MatType>
  struct EigenFromPyConverter< eigenpy::Ref<MatType> >
  {
    static void registration()
    {
      bp::converter::registry::push_back
      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
       &EigenFromPy<MatType>::construct,bp::type_id<MatType>());
    }
  };
#endif

  template<typename MatType>
  void enableEigenPySpecific()
  {
    numpy_import_array();
    if(check_registration<MatType>()) return;

    bp::to_python_converter<MatType,EigenToPy<MatType> >();
    EigenFromPyConverter<MatType>::registration();

  }

} // namespace eigenpy

#endif // ifndef __eigenpy_details_hpp__
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <iosfwd>     //For stream support

#include "traits_lite.hpp"
#include "iterator.hpp"

// CRTP Classes
#include "crtp/comparable.hpp"
#include "crtp/value_testable.hpp"
#include "crtp/dim_testable.hpp"

namespace etl {

template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
struct binary_expr final :
          comparable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
        , dim_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
        , value_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
        {
private:
    static_assert(cpp::or_c<
        cpp::and_c<is_etl_expr<LeftExpr>, std::is_same<RightExpr, scalar<T>>>,
        cpp::and_c<is_etl_expr<RightExpr>, std::is_same<LeftExpr, scalar<T>>>,
        cpp::and_c<is_etl_expr<LeftExpr>, is_etl_expr<RightExpr>>>::value,
        "One argument must be an ETL expression and the other one convertible to T");

    using this_type = binary_expr<T, LeftExpr, BinaryOp, RightExpr>;

    LeftExpr _lhs;
    RightExpr _rhs;

public:
    using        value_type = T;
    using       memory_type = void;
    using const_memory_type = void;

    //Cannot be constructed with no args
    binary_expr() = delete;

    //Construct a new expression
    binary_expr(LeftExpr l, RightExpr r) : _lhs(std::forward<LeftExpr>(l)), _rhs(std::forward<RightExpr>(r)) {
        //Nothing else to init
    }

    //Expresison can be copied and moved
    binary_expr(const binary_expr& e) = default;
    binary_expr(binary_expr&& e) = default;

    //Expressions are invariant
    binary_expr& operator=(const binary_expr& e) = delete;
    binary_expr& operator=(binary_expr&& e) = delete;

    //Accessors

    std::add_lvalue_reference_t<LeftExpr> lhs(){
        return _lhs;
    }

    cpp::add_const_lvalue_t<LeftExpr> lhs() const {
        return _lhs;
    }

    std::add_lvalue_reference_t<RightExpr> rhs(){
        return _rhs;
    }

    cpp::add_const_lvalue_t<RightExpr> rhs() const {
        return _rhs;
    }

    //Apply the expression

    value_type operator[](std::size_t i) const {
        return BinaryOp::apply(lhs()[i], rhs()[i]);
    }

    intrinsic_type<value_type> load(std::size_t i) const {
        return BinaryOp::load(lhs().load(i), rhs().load(i));
    }

    template<typename... S, cpp_enable_if(sizeof...(S) == sub_size_compare<this_type>::value)>
    value_type operator()(S... args) const {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return BinaryOp::apply(lhs()(args...), rhs()(args...));
    }

    //TODO Simplify the next two SFINAE functions

    template <typename ST = T, typename L = LeftExpr, typename B = BinaryOp, typename R = RightExpr, cpp_enable_if((sub_size_compare<binary_expr<ST, L, B, R>>::value > 1))>
    auto operator()(std::size_t i){
        return sub(*this, i);
    }

    template <typename ST = T, typename L = LeftExpr, typename B = BinaryOp, typename R = RightExpr, cpp_enable_if((sub_size_compare<binary_expr<ST, L, B, R>>::value > 1))>
    auto operator()(std::size_t i) const {
        return sub(*this, i);
    }

    iterator<const this_type> begin() const noexcept {
        return {*this, 0};
    }

    iterator<const this_type> end() const noexcept {
        return {*this, size(*this)};
    }
};

template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
std::ostream& operator<<(std::ostream& os, const binary_expr<T, LeftExpr, BinaryOp, RightExpr>& expr){
    if(simple_operator<BinaryOp>::value){
        return os << "(" << expr.lhs() << ' ' << BinaryOp::desc() << ' ' << expr.rhs() << ")";
    } else {
        return os << BinaryOp::desc() << "(" << expr.lhs() << ", " << expr.rhs() << ")";
    }
}

} //end of namespace etl
<commit_msg>Allow scalar-scalar binary expression<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <iosfwd>     //For stream support

#include "traits_lite.hpp"
#include "iterator.hpp"

// CRTP Classes
#include "crtp/comparable.hpp"
#include "crtp/value_testable.hpp"
#include "crtp/dim_testable.hpp"

namespace etl {

template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
struct binary_expr final :
          comparable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
        , dim_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
        , value_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
        {
private:
    static_assert(cpp::or_c<
        cpp::and_c<std::is_same<LeftExpr, scalar<T>>, std::is_same<RightExpr, scalar<T>>>,
        cpp::and_c<is_etl_expr<LeftExpr>, std::is_same<RightExpr, scalar<T>>>,
        cpp::and_c<is_etl_expr<RightExpr>, std::is_same<LeftExpr, scalar<T>>>,
        cpp::and_c<is_etl_expr<LeftExpr>, is_etl_expr<RightExpr>>>::value,
        "One argument must be an ETL expression and the other one convertible to T");

    using this_type = binary_expr<T, LeftExpr, BinaryOp, RightExpr>;

    LeftExpr _lhs;
    RightExpr _rhs;

public:
    using        value_type = T;
    using       memory_type = void;
    using const_memory_type = void;

    //Cannot be constructed with no args
    binary_expr() = delete;

    //Construct a new expression
    binary_expr(LeftExpr l, RightExpr r) : _lhs(std::forward<LeftExpr>(l)), _rhs(std::forward<RightExpr>(r)) {
        //Nothing else to init
    }

    //Expresison can be copied and moved
    binary_expr(const binary_expr& e) = default;
    binary_expr(binary_expr&& e) = default;

    //Expressions are invariant
    binary_expr& operator=(const binary_expr& e) = delete;
    binary_expr& operator=(binary_expr&& e) = delete;

    //Accessors

    std::add_lvalue_reference_t<LeftExpr> lhs(){
        return _lhs;
    }

    cpp::add_const_lvalue_t<LeftExpr> lhs() const {
        return _lhs;
    }

    std::add_lvalue_reference_t<RightExpr> rhs(){
        return _rhs;
    }

    cpp::add_const_lvalue_t<RightExpr> rhs() const {
        return _rhs;
    }

    //Apply the expression

    value_type operator[](std::size_t i) const {
        return BinaryOp::apply(lhs()[i], rhs()[i]);
    }

    intrinsic_type<value_type> load(std::size_t i) const {
        return BinaryOp::load(lhs().load(i), rhs().load(i));
    }

    template<typename... S, cpp_enable_if(sizeof...(S) == sub_size_compare<this_type>::value)>
    value_type operator()(S... args) const {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return BinaryOp::apply(lhs()(args...), rhs()(args...));
    }

    //TODO Simplify the next two SFINAE functions

    template <typename ST = T, typename L = LeftExpr, typename B = BinaryOp, typename R = RightExpr, cpp_enable_if((sub_size_compare<binary_expr<ST, L, B, R>>::value > 1))>
    auto operator()(std::size_t i){
        return sub(*this, i);
    }

    template <typename ST = T, typename L = LeftExpr, typename B = BinaryOp, typename R = RightExpr, cpp_enable_if((sub_size_compare<binary_expr<ST, L, B, R>>::value > 1))>
    auto operator()(std::size_t i) const {
        return sub(*this, i);
    }

    iterator<const this_type> begin() const noexcept {
        return {*this, 0};
    }

    iterator<const this_type> end() const noexcept {
        return {*this, size(*this)};
    }
};

template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
std::ostream& operator<<(std::ostream& os, const binary_expr<T, LeftExpr, BinaryOp, RightExpr>& expr){
    if(simple_operator<BinaryOp>::value){
        return os << "(" << expr.lhs() << ' ' << BinaryOp::desc() << ' ' << expr.rhs() << ")";
    } else {
        return os << BinaryOp::desc() << "(" << expr.lhs() << ", " << expr.rhs() << ")";
    }
}

} //end of namespace etl
<|endoftext|>