#ifndef GROUP_H_ #define GROUP_H_ #include #include /* * requires Ops : struct { * typedef KeyType; * typedef ProjType; * typedef GroupType; * * KeyType key(Source::ElementType&); * ProjType project(Source::ElementType&); * void step(Source::ElementType&); * * GroupType finish(); * } * * yields sequence (Source::ElementType, ) */ template class Group { private: typedef typename Ops::KeyType KeyType; typedef typename Ops::ProjType ProjType; typedef typename Ops::GroupType GroupType; public: typedef std::pair ElementType; typedef typename Source::MarkerType MarkerType; public: Group(Source source, Ops ops) : source(source), ops(ops), sourceIsActive(false) { } bool step() { if(!this->sourceIsActive && !this->source.step() ) return false; groupCurrentSet(); return true; } ElementType* get() { return ¤t; } MarkerType mark() const { return this->currentMark; } void restore(MarkerType mark) { this->source.restore(mark); groupCurrentSet(); } private: void groupCurrentSet() { typename Source::ElementType* row = this->source.get(); this->currentMark = this->source.mark(); this->current.first = this->ops.project(*row); this->ops.step(*row); KeyType currentKey = this->ops.key(*row); while(true) { if(!this->source.step() ) { this->sourceIsActive = false; break; } row = this->source.get(); if(!(currentKey == this->ops.key(*row) ) ) { this->sourceIsActive = true; break; } this->ops.step(*row); } this->current.second = this->ops.finish(); } private: Source source; Ops ops; ElementType current; typename Source::MarkerType currentMark; bool sourceIsActive; }; namespace db { template struct GroupOp { Ops ops; template friend Group operator|(Source source, const GroupOp& fn) { return Group(source, fn.ops); } }; template inline GroupOp groupBy(Ops ops) { GroupOp result = {ops}; return result; } } #endif