Skip to content

Instantly share code, notes, and snippets.

@mntone
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mntone/1042bb2edca272d425b0 to your computer and use it in GitHub Desktop.
Save mntone/1042bb2edca272d425b0 to your computer and use it in GitHub Desktop.
C++ および C++/CX で Linq っぽいことを可能にするクラス
#pragma once
#include <numeric>
#include <type_traits>
#include <vector>
#ifdef __cplusplus_winrt
#include <collections.h>
#endif
namespace Linq {
namespace Details {
template<typename T>
struct Wrap
{
typedef T type;
};
template<typename T>
inline const T& MakeWrap( const T& t )
{
return t;
}
template<typename T>
inline const T& Unwrap( const T& t )
{
return t;
}
#ifdef __cplusplus_winrt
template<typename T>
struct Wrap<T^>
: public ::std::conditional<__is_winrt_agile( T ), T^, ::Platform::Agile<T^>>
{ };
template<typename T>
inline typename ::std::enable_if<!__is_winrt_agile( T ), ::Platform::Agile<T^>>::type MakeWrap( T^ const& t )
{
return ::Platform::Agile<T^>( t );
}
template<typename T>
inline T^ Unwrap( const ::Platform::Agile<T^>& a )
{
return a.Get();
}
#endif
}
template<typename T>
class Vectorable
{
private:
using SizeType = typename ::std::vector<typename Details::Wrap<T>::type>::size_type;
using ItrType = typename ::std::vector<typename Details::Wrap<T>::type>::iterator;
public:
Vectorable( SizeType size )
: data_( size )
{ }
template<typename FwdItr>
Vectorable( FwdItr begin, FwdItr end )
: Vectorable( end - begin + 1)
{
::std::transform(
begin,
end,
::std::begin( data_ ),
[]( T value ) { return Details::MakeWrap( value ); } );
}
ItrType Begin()
{
return ::std::begin( data_ );
}
ItrType End()
{
return ::std::end( data_ );
}
template<typename S>
Vectorable<S> Cast()
{
Vectorable<S> ret( data_.size() );
::std::transform(
::std::cbegin( data_ ),
::std::cend( data_ ),
::std::begin( ret.data_ ),
[]( typename Details::Wrap<T>::type value ) { return Details::MakeWrap( static_cast<S>( Details::Unwrap( value ) ) ); } );
return ret;
}
T Sum()
{
static_assert( ::std::is_arithmetic<typename Details::Wrap<T>::type>::value, "T is arithmeticable only." );
return ::std::accumulate( ::std::cbegin( data_ ), ::std::cend( data_ ), 0 );
}
T Average()
{
return Sum() / data_.size();
}
T Minimum()
{
static_assert( ::std::is_arithmetic<typename Details::Wrap<T>::type>::value, "T is arithmeticable only." );
return *::std::min_element( ::std::cbegin( data_ ), ::std::cend( data_ ) );
}
T Maximum()
{
static_assert( ::std::is_arithmetic<typename Details::Wrap<T>::type>::value, "T is arithmeticable only." );
return *::std::max_element( ::std::cbegin( data_ ), ::std::cend( data_ ) );
}
#ifdef __cplusplus_winrt
template<typename T>
Vectorable OfType()
{
return OfType( T::typeid );
}
Vectorable OfType( Windows::UI::Xaml::Interop::TypeName typeName )
{
static_assert( __is_valid_winrt_type( typename Details::Wrap<T>::type ), "T is winrt type only." );
Vectorable ret( data_.size() );
auto itr = ::std::copy_if(
::std::cbegin( data_ ),
::std::cend( data_ ),
::std::begin( ret.data_ ),
[typeName]( typename Details::Wrap<T>::type value )
{
return ::Windows::UI::Xaml::Interop::TypeName( Details::Unwrap( value )->GetType() ).Name == typeName.Name;
} );
ret.data_.resize( ::std::distance( ::std::begin( ret.data_ ), itr ) );
return ::std::move( ret );
}
#endif
::std::vector<T> to_vector()
{
::std::vector<T> ret( data_.size() );
::std::transform(
::std::cbegin( data_ ),
::std::cend( data_ ),
::std::begin( ret ),
[]( typename Details::Wrap<T>::type value ) { return Details::Unwrap( value ); } );
return ::std::move( ret );
}
#ifdef __cplusplus_winrt
Windows::Foundation::Collections::IVector<T>^ ToVector()
{
return ref new Platform::Collections::Vector<T>( ::std::move( to_vector() ) );
}
Windows::Foundation::Collections::IVectorView<T>^ ToVectorView()
{
return ref new Platform::Collections::VectorView<T>( ::std::move( to_vector() ) );
}
#endif
private:
::std::vector<typename Details::Wrap<T>::type> data_;
};
template<typename T>
using RemoveIteratorT = ::std::remove_const_t<::std::remove_reference_t<::std::remove_const_t<T>>>;
template<class Container>
inline auto From( const Container& container ) -> Vectorable<RemoveIteratorT<decltype( *::std::begin( container ) )>>
{
return Vectorable<RemoveIteratorT<decltype( *::std::begin( container ) )>>( ::std::cbegin( container ), ::std::cend( container ) );
}
template<class Integer>
inline Vectorable<Integer> Range( Integer from, Integer to )
{
static_assert( ::std::is_integral<Integer>::value, "T is integer only." );
Vectorable<Integer> ret( to - from + 1 );
::std::generate(
ret.Begin(),
ret.End(),
[&from] { return from++; } );
return ret;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment