Last active
August 29, 2015 14:02
-
-
Save mntone/1042bb2edca272d425b0 to your computer and use it in GitHub Desktop.
C++ および C++/CX で Linq っぽいことを可能にするクラス
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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