#include <iostream>

template< typename T >
struct v_traits;

template< typename T, int index>
struct access {};

struct float3 { float x, y, z; };

std::ostream & operator<<( std::ostream & os, const float3 & v ) {
	os << "{" << v.x << ", " << v.y << ", " << v.z << "}";
	return os;
}

template<>
struct v_traits<float3> {
	typedef float3 vector_type;
	typedef float element_type;
	typedef element_type & element_ref;
};

template<>
struct access<float3,0> {
	static float & get( float3 & v ) { return v.x; }
};

template<>
struct access<float3,1> {
	static float & get( float3 & v ) { return v.y; }
};

template<>
struct access<float3,2> {
	static float & get( float3 & v ) { return v.z; }
};

template< int index, typename T >
typename v_traits<T>::element_ref get( T & v ) {
	return access<T,index>::get( v );
}

template< typename T0 >
struct vec1_view {
	T0 & x;

    vec1_view( T0 & x_ ) : x(x_) {}
	vec1_view( vec1_view && v ) : x(v.x) {}
    
    vec1_view & operator=( T0 x_ ) {
        x = x_;
        return *this;
    }

    template< typename U0 >
    vec1_view & operator=( const vec1_view<U0> & v ) {
        x = v.x;
        return *this;
    }

	vec1_view & operator=( const vec1_view & v )  {
		x = v.x;
		return *this;
	}
};

template< typename T0, typename T1 >
struct vec2_view {
	T0 & x;
	T1 & y;

    vec2_view( T0 & x_, T1 & y_ ) : x(x_), y(y_) {}
	vec2_view( vec2_view && v ) : x(v.x), y(v.y) {}

	vec2_view & operator=( const vec2_view & v )  {
		x = v.x;
		y = v.y;
		return *this;
	}

	template< typename U0, typename U1 >
	vec2_view & operator=( const vec2_view<U0, U1> & v ) {
		x = v.x;
		y = v.y;
		return *this;
	}
};

namespace swizzle {
#define SWIZZLE_ENUM( mask ) enum swizzle_##mask { mask };
    SWIZZLE_ENUM( x )
    SWIZZLE_ENUM( y )
    SWIZZLE_ENUM( z )
    SWIZZLE_ENUM( xx )
    SWIZZLE_ENUM( xy )
    SWIZZLE_ENUM( xz )
    SWIZZLE_ENUM( yx )
    SWIZZLE_ENUM( yy )
    SWIZZLE_ENUM( yz )
    SWIZZLE_ENUM( zx )
    SWIZZLE_ENUM( zy )
    SWIZZLE_ENUM( zz )    
}

#define SWIZZLE_OP1( mask, a )                                    \
template< typename V >                                            \
vec1_view<typename v_traits<V>::element_type>                     \
    operator,( V & v, swizzle::swizzle_##mask ) {                 \
    typedef typename v_traits<V>::element_type element_type;      \
    typedef vec1_view<element_type> view_type;                    \
    return view_type( get<a>( v ) );                              \
}                                                                 \

SWIZZLE_OP1( x, 0 )
SWIZZLE_OP1( y, 1 )
SWIZZLE_OP1( z, 2 )

#define SWIZZLE_OP2( mask, a, b )                                                   \
template< typename V >                                                              \
vec2_view<typename v_traits<V>::element_type, typename v_traits<V>::element_type>   \
operator,( V & v, swizzle::swizzle_##mask ) {                                       \
    typedef typename v_traits<V>::element_type element_type;                        \
    typedef vec2_view<element_type, element_type> view_type;                        \
    return view_type( get<a>( v ), get<b>( v ) );			                        \
}                                                                                   \

SWIZZLE_OP2( xx, 0, 0 )
SWIZZLE_OP2( xy, 0, 1 )
SWIZZLE_OP2( xz, 0, 2 )
SWIZZLE_OP2( yx, 1, 0 )
SWIZZLE_OP2( yy, 1, 1 )
SWIZZLE_OP2( yz, 1, 2 )
SWIZZLE_OP2( zx, 2, 0 )
SWIZZLE_OP2( zy, 2, 1 )
SWIZZLE_OP2( zz, 2, 2 )


int main() {
    float3 v;
    using namespace swizzle;
    (v,x) = 1.0f;
    (v,y) = 2.0f;
    (v,z) = 3.0f;

	std::cout << v << std::endl;

    (v,yz) = (v,xx);

	std::cout << v << std::endl;
    return 0;
}
