/* * Copyright (c) 2011-2012, Attila Gobi and Zalan Szugyi * All rights reserved. * * This software was developed by Attila Gobi and Zalan Szugyi. * The project was supported by the European Union and co-financed by the * European Social Fund (grant agreement no. TAMOP 4.2.1./B-09/1/KMR-2010-0003) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __stream_h__ #define __stream_h__ #include #include #include #include #if __GNUC__ > 4 || \ (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7)) #define HAVE_LITERALS #endif template struct storage_type { typedef typename std::conditional< std::is_lvalue_reference::type>::value, typename std::remove_const::type, typename std::remove_reference::type>::type >::type type; }; template struct stream { protected: struct impl; public: typedef T value_type; stream(const stream &o) : impl_(o.impl_->clone()) { } stream(stream &&o) : impl_(0) { std::swap(impl_, o.impl_); } stream & operator = (stream &&o) { if(this != &o) { std::swap(impl_, o.impl_); return *this; } } ~stream() { delete impl_; } struct iterator { iterator& operator ++() { (*impl_)->next(*this); return *this; } const T& operator *() const { return (*impl_)->get(*this); } friend class stream; protected: iterator(impl ** impl) :impl_(impl) { } impl **impl_; }; iterator begin() const { return iterator(&impl_); } protected: struct impl { virtual ~impl() {} virtual const T &get(const iterator &) = 0; virtual void next(iterator &) = 0; virtual impl* clone() = 0; }; mutable impl * impl_; stream(impl *i) :impl_(i) { } template struct addimpl: public impl { addimpl(const T &a, ST &&s) : a_(a), s_(std::forward(s)) { } const T &get(const iterator &) { return a_; } void next(iterator &it) { it.impl_ = const_cast(&s_.impl_); } impl *clone() { return new addimpl(a_, std::forward(s_)); } private: const T a_; typename storage_type::type s_; }; template struct mapimpl2: public impl { mapimpl2(Op op, ST &&s) :s_(std::forward(s)), it1(s_.begin()), op_(op) { } const T &get(const iterator &it) { *(it.impl_)=new addimpl&&>(op_(*it1), stream(this)); ++it1; return *it; } void next(iterator &it) { *(it.impl_)=new addimpl&&>(op_(*it1), stream(this)); ++it1; ++it; } impl *clone() { return new mapimpl2(op_, std::forward(s_)); } private: typename storage_type::type s_; iterator it1; Op op_; }; template struct mapimpl: public impl { mapimpl(Op op, ST &&s) : s_(std::forward(s)), op_(op) { } const T &get(const iterator &it) { impl *x = new mapimpl2(op_, std::forward(s_)); *(it.impl_) = x; delete this; return *it; } void next(iterator &it) { impl *x = new mapimpl2(op_, std::forward(s_)); *(it.impl_) = x; delete this; ++it; } impl *clone() { return new mapimpl(op_, std::forward(s_)); } private: typename storage_type::type s_; Op op_; }; template struct zipimpl: public impl { zipimpl(Op op, ST1 &&s1, ST2 &&s2) :s1_(std::forward(s1)), s2_(std::forward(s2)), op_(op) { } const T &get(const iterator &it) { impl *x = new zipimpl2(op_, std::forward(s1_), std::forward(s2_)); *(it.impl_) = x; delete this; return *it; } void next(iterator &it) { impl *x = new zipimpl2(op_, std::forward(s1_), std::forward(s2_)); *(it.impl_) = x; delete this; ++it; } impl *clone() { return new zipimpl(op_, std::forward(s1_), std::forward(s2_)); } private: typename storage_type::type s1_; typename storage_type::type s2_; Op op_; }; template struct zipimpl2: public impl { zipimpl2(Op op, ST1 &&s1, ST2 &&s2) :s1_(std::forward(s1)),s2_(std::forward(s2)), it1(s1_.begin()), it2(s2_.begin()), op_(op) { } const T &get(const iterator &it) { *(it.impl_)=new addimpl&&>(op_(*it1, *it2), stream(this)); ++it1; ++it2; return *it; } void next(iterator &it) { *(it.impl_)=new addimpl&&>(op_(*it1, *it2), stream(this)); ++it1; ++it2; ++it; } impl *clone() { return new zipimpl2(op_, std::forward(s1_), std::forward(s2_)); } private: typename storage_type::type s1_; typename storage_type::type s2_; iterator it1, it2; Op op_; }; public: template friend stream operator <<= (const U& a, S && s); template static stream zipwith(Op op, ST1 &&s1, ST2 &&s2) { return stream(new zipimpl(op, std::forward(s1), std::forward(s2))); } template static stream map(Op op, ST1 &&s1) { return stream(new mapimpl(op, std::forward(s1))); } static stream pure(const T& v) { stream s = v<<=s; return s; } }; template struct stream_value_type { typedef typename std::remove_reference::type::value_type type; }; template ::type> stream operator <<= (const U& a, S && s) { return stream(new typename stream::template addimpl(a, std::forward(s))); } template::type> stream operator +(ST1 &&s1, ST2 &&s2) { return stream::zipwith(std::plus(), std::forward(s1), std::forward(s2)); } template::type> stream operator -(ST1 &&s1, ST2 &&s2) { return stream::zipwith(std::minus(), std::forward(s1), std::forward(s2)); } template::type> stream operator *(ST1 &&s1, ST2 &&s2) { return stream::zipwith(std::multiplies(), std::forward(s1), std::forward(s2)); } template::type> stream operator /(ST1 &&s1, ST2 &&s2) { return stream::zipwith(std::divides(), std::forward(s1), std::forward(s2)); } template::type> stream operator %(ST1 &&s1, ST2 &&s2) { return stream::zipwith(std::modulus(), std::forward(s1), std::forward(s2)); } template::type> stream operator -(ST &&s) { return stream::map(std::negate(), std::forward(s)); } #ifdef HAVE_LITERALS struct stream_proxy { stream_proxy(unsigned long long i): x(i) {} template operator stream () { stream a = static_cast(x)<<=a; return a; } unsigned long long x; }; stream_proxy operator "" _s (unsigned long long i) { return stream_proxy(i); } #endif//HAVE_LITERALS #endif//__stream_h__