#ifndef TABLE_H_ #define TABLE_H_ /* This program is written by Alexander Shirokov on Sunday November 13, 2011 in Toronto Canada on a personal initiative. The program is available for anyone who wishes to use it, without any restrictions or warranties whatsoever. The program is originally available for download at: http://www.cita.utoronto.ca/~shirokov/soft/table */ #include #include #include #include #include #include #include namespace CHAR { namespace CHR { const char TAB = '\t'; }; namespace STR { const std::string TAB = std::string(1,CHR::TAB); }; }; #define endl_r std::endl template struct vlist_of : public std::vector { vlist_of(const T& t) { (*this)(t); } vlist_of& operator()(const T& t) { this->push_back(t); return *this; } }; namespace Table { namespace Type { typedef std::string colname; typedef std::vector header; typedef std::string elem; typedef std::vector elemvec; typedef std::map indexmap; typedef std::pair pairelem; typedef std::map elemap; }; // Convert vector of keys into map key to index. template std::map indexmap(const std::vector & vector) { typedef typename std::map map_t; map_t map; typename std::vector::const_iterator it; size_t i = 0; for(it = vector.begin(); it != vector.end(); it++){ const std::pair pair(*it,i); std::pair ins = map.insert( pair ); if( ins.second == false ){ throw std::domain_error(std::string("no duplicates allowed in header: ")+*it); } ++i; } return map; } class RowCls { public: RowCls(const bool chk_nodup) : m_chk_nodup(chk_nodup) {} Type::elem & operator[](const Type::colname & colname) { const std::pair insertion = m_elemap.insert(Type::pairelem(colname,"")); // Throw an exception if chk_nodup option is set and the key is duplicate if( m_chk_nodup == true && insertion.second == false ){ throw std::domain_error(std::string("chk_nodup: column value already inserted: ") +colname); } return insertion.first->second; } // Representative string std::string string(const std::string aweql, const std::string awcol) const { Type::elemap::const_iterator it; std::stringstream ss; for( Type::elemap::const_iterator it = m_elemap.begin() ; it != m_elemap.end(); ++it ) { const Type::colname colname = it->first; const Type::elem elem = it->second; if (it != m_elemap.begin()) ss << awcol; ss << colname << aweql << elem; } return ss.str(); } friend std::ostream & operator<<(std::ostream & fh, const RowCls & T) { fh << T.string(":",","); return fh; } // Table row formatted representative string std::string tablestring(const Type::indexmap indexmap, const bool chk_header, const std::string awlqt, const std::string awrqt, const std::string awcol ) const { const size_t size = indexmap.size(); Type::elemvec elems(size,""); for( Type::elemap::const_iterator it = m_elemap.begin() ; it != m_elemap.end(); ++it ) { const Type::colname colname = it->first; const Type::elem elem = it->second; Type::indexmap::const_iterator it = indexmap.find(colname); if( it != indexmap.end() ){ const size_t index = it->second; elems[index] = elem; } else { if( chk_header == true ){ throw std::domain_error("chk_header: invalid column name being inserted: "+ std::string(colname) ); } } } std::stringstream ss; for(Type::elemvec::const_iterator it = elems.begin(); it != elems.end(); ++it){ if( it != elems.begin() ) ss << awcol; ss << awlqt << *it << awrqt; } return ss.str(); } private: const bool m_chk_nodup; Type::elemap m_elemap; }; class MemoryTableCls { public: MemoryTableCls(const Type::header header) : m_header(header) , m_indexmap(indexmap(header)), m_size( header.size() ) {} template MemoryTableCls & operator+=(const T & collector) { m_rows.push_back( collector ); return *this; } std::string tablestring(const bool chk_header, const std::string awlqt, const std::string awrqt, const std::string awcol ) const { std::stringstream fh; // The header { size_t i = -1; for(Type::header::const_iterator it = m_header.begin(); it != m_header.end(); ++it) { ++i; fh << awlqt << *it << awrqt; if( i < m_size-1 ) fh << awcol; } } fh << endl_r; // The body { std::deque::const_iterator it; for(it = m_rows.begin(); it != m_rows.end(); ++it){ const RowCls & c = *it; fh << c.tablestring(m_indexmap,chk_header,awlqt,awrqt,awcol) << endl_r; } } return fh.str(); } friend std::ostream & operator<<(std::ostream & fh, const MemoryTableCls & T) { const std::string awlqt = ""; const std::string awrqt = ""; const std::string awcol = CHAR::STR::TAB; const bool chk_header = false; fh << T.tablestring(chk_header,awlqt,awrqt,awcol); return fh; } private: const Type::header m_header; const Type::indexmap m_indexmap; const size_t m_size; std::deque m_rows; }; class PipeTableCls { public: PipeTableCls(std::ostream &ofh, const Type::header header, const bool chk_header, const std::string awlqt, const std::string awrqt, const std::string awcol ) : m_header(header) , m_indexmap(indexmap(header)), m_size( header.size() ), m_ofh(ofh), m_chk_header(chk_header), m_awlqt(awlqt), m_awrqt(awrqt), m_awcol(awcol) { // The header { size_t i = -1; for(Type::header::const_iterator it = m_header.begin(); it != m_header.end(); ++it) { ++i; m_ofh << awlqt << *it << awrqt; if( i < m_size-1 ) m_ofh << awcol; } } // Write the newline m_ofh << endl_r; } template PipeTableCls & operator+=(const T & collector) { // The body m_ofh << collector.tablestring( m_indexmap,m_chk_header,m_awlqt,m_awrqt,m_awcol) << endl_r; return *this; } private: const Type::header m_header; const Type::indexmap m_indexmap; const size_t m_size; const bool m_chk_header; const std::string m_awlqt; const std::string m_awrqt; const std::string m_awcol; std::ostream & m_ofh; }; }; #endif