1 #ifndef UTIL_NCBITABLE__HPP
2 #define UTIL_NCBITABLE__HPP
3 
4 /* $Id: ncbi_table.hpp 574980 2018-11-21 14:24:48Z ucko $
5 * ===========================================================================
6 *
7 *                            public DOMAIN NOTICE
8 *               National Center for Biotechnology Information
9 *
10 *  This software/database is a "United States Government Work" under the
11 *  terms of the United States Copyright Act.  It was written as part of
12 *  the author's official duties as a United States Government employee and
13 *  thus cannot be copyrighted.  This software/database is freely available
14 *  to the public for use. The National Library of Medicine and the U.S.
15 *  Government have not placed any restriction on its use or reproduction.
16 *
17 *  Although all reasonable efforts have been taken to ensure the accuracy
18 *  and reliability of the software and data, the NLM and the U.S.
19 *  Government do not and cannot warrant the performance or results that
20 *  may be obtained by using this software or data. The NLM and the U.S.
21 *  Government disclaim all warranties, express or implied, including
22 *  warranties of performance, merchantability or fitness for any particular
23 *  purpose.
24 *
25 *  Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author:  Anatoliy Kuznetsov
30 *
31 * File Description:
32 *   NCBI table
33 *
34 */
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbiexpt.hpp>
37 
38 BEGIN_NCBI_SCOPE
39 
40 class NCBI_XUTIL_EXPORT CNcbiTable_Exception : EXCEPTION_VIRTUAL_BASE public CException
41 {
42 public:
43     /// Exception types
44     enum EErrCode {
45         eRowNotFound,          ///< Row not found
46         eColumnNotFound,       ///< Column not found
47         eRowAlreadyExists,     ///< Row id has been assigned before
48         eColumnAlreadyExists   ///< Column id has been assigned before
49     };
50 
51     virtual const char* GetErrCodeString(void) const override;
52 
53     NCBI_EXCEPTION_DEFAULT(CNcbiTable_Exception, CException);
54 };
55 
56 
57 
58 /// Template class to create a table with custom row-column access
59 ///
60 /// Table provides two access modes one is using custom types
61 /// associated with rows and columns and another using rows and columns
62 /// integer indexes.
63 ///
64 template<class TValue, class TRow, class TColumn>
65 class CNcbiTable
66 {
67 public:
68     typedef map<TRow,    unsigned int>    TRowMap;
69     typedef map<TColumn, unsigned int>    TColumnMap;
70     typedef TValue                        TValueType;
71 
72     typedef vector<TValue>    TRowType;
73 
74 public:
75     CNcbiTable();
76     /// Construction.
77     /// Creates row x cols table without any row-column association
78     CNcbiTable(unsigned int rows, unsigned int cols);
79 
80     CNcbiTable(const CNcbiTable& table);
operator =(const CNcbiTable & table)81     CNcbiTable& operator=(const CNcbiTable& table)
82     {
83         x_Free();
84         x_Copy(table);
85         return *this;
86     }
87 
88     ~CNcbiTable();
89 
90 
91     /// Number of rows
92     unsigned int Rows() const;
93     /// Number of column
94     unsigned int Cols() const;
95 
96     /// Add column to the table, column recieves name "col"
97     void AddColumn(const TColumn& col);
98     /// Add row to the table, column recieves name "row"
99     void AddRow(const TRow& row);
100 
101     /// Set up row name
102     void AssociateRow(const TRow& row, unsigned int row_idx);
103     /// Set up column name
104     void AssociateColumn(const TColumn& col, unsigned int col_idx);
105 
106     /// Change table size
107     void Resize(unsigned int rows,
108                 unsigned int cols);
109 
110     /// Change table size, new table elements initialized with value
111     void Resize(unsigned int rows,
112                 unsigned int cols,
113                 const TValue& v);
114 
115     /// Get table row
116     const TRowType& GetRow(const TRow& row) const;
117     /// Get table row by row index
118     const TRowType& GetRowVector(unsigned int row_idx) const;
119     /// Get table row by row index
120     TRowType& GetRowVector(unsigned int row_idx);
121 
122     /// Get table element
123     const TValueType& GetElement(const TRow& row, const TColumn& col) const;
124     /// Get table element
125     TValueType& GetElement(const TRow& row, const TColumn& col);
126 
127     /// Get table element
operator ()(const TRow & row,const TColumn & col) const128     const TValue& operator()(const TRow& row, const TColumn& col) const
129     {
130         return GetElement(row, col);
131     }
132     /// Get table element
operator ()(const TRow & row,const TColumn & col)133     TValue& operator()(const TRow& row, const TColumn& col)
134     {
135         return GetElement(row, col);
136     }
137 
138     /// Get column index
139     unsigned int ColumnIdx(const TColumn& col) const;
140     /// Get row index
141     unsigned int RowIdx(const TRow& row) const;
142 
143     /// Get column name
144     const TColumn& Column(unsigned int idx) const;
145     /// Get row name
146     const TRow& Row(unsigned int idx) const;
147 
148     /// Access table element by index
149     const TValueType& GetCell(unsigned int row_idx, unsigned int col_idx) const;
150 
151     /// Access table element by index
152     TValueType& GetCell(unsigned int row_idx, unsigned int col_idx);
153 protected:
154 
155     void x_Free();
156     void x_Copy(const CNcbiTable& table);
157 
158 protected:
159     typedef vector<TRowType*>   TRowCollection;
160 
161 protected:
162     unsigned int    m_Rows;      ///< Number of rows
163     unsigned int    m_Cols;      ///< Number of columns
164 
165     TRowMap         m_RowMap;     ///< Row name to index
166     TColumnMap      m_ColumnMap;  ///< Column name to index
167 
168     TRowCollection  m_Table;
169 };
170 
171 /////////////////////////////////////////////////////////////////////////////
172 //
173 //  CNcbiTable<TValue, TRow, TColumn>
174 //
175 
176 template<class TValue, class TRow, class TColumn>
CNcbiTable()177 CNcbiTable<TValue, TRow, TColumn>::CNcbiTable()
178 : m_Rows(0),
179   m_Cols(0)
180 {
181 }
182 
183 template<class TValue, class TRow, class TColumn>
CNcbiTable(unsigned int rows,unsigned int cols)184 CNcbiTable<TValue, TRow, TColumn>::CNcbiTable(unsigned int rows,
185                                               unsigned int cols)
186 : m_Rows(rows),
187   m_Cols(cols)
188 {
189     m_Table.reserve(m_Rows);
190     for (unsigned int i = 0; i < m_Rows; ++i) {
191         TRowType* r = new TRowType(m_Cols);
192         m_Table.push_back(r);
193     }
194 }
195 
196 template<class TValue, class TRow, class TColumn>
CNcbiTable(const CNcbiTable<TValue,TRow,TColumn> & table)197 CNcbiTable<TValue, TRow, TColumn>::CNcbiTable(
198                  const CNcbiTable<TValue, TRow, TColumn>& table)
199 {
200     x_Copy(table);
201 }
202 
203 template<class TValue, class TRow, class TColumn>
x_Copy(const CNcbiTable & table)204 void CNcbiTable<TValue, TRow, TColumn>::x_Copy(const CNcbiTable& table)
205 {
206     m_Rows = table.Rows();
207     m_Cols = table.Cols();
208 
209     m_Table.resize(0);
210     m_Table.reserve(m_Rows);
211     for (unsigned int i = 0; i < m_Rows; ++i) {
212         const TRowType& src_row = table.GetRowVector(i);
213         TRowType* r = new TRowType(src_row);
214         m_Table.push_back(r);
215     }
216 
217     m_RowMap = table.m_RowMap;
218     m_ColumnMap = table.m_ColumnMap;
219 }
220 
221 
222 template<class TValue, class TRow, class TColumn>
~CNcbiTable()223 CNcbiTable<TValue, TRow, TColumn>::~CNcbiTable()
224 {
225     x_Free();
226 }
227 
228 template<class TValue, class TRow, class TColumn>
x_Free()229 void CNcbiTable<TValue, TRow, TColumn>::x_Free()
230 {
231     NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
232         TRowType* r = *it;
233         delete r;
234     }
235     m_Table.resize(0);
236 }
237 
238 
239 template<class TValue, class TRow, class TColumn>
Rows() const240 unsigned int CNcbiTable<TValue, TRow, TColumn>::Rows() const
241 {
242     return m_Rows;
243 }
244 
245 template<class TValue, class TRow, class TColumn>
Cols() const246 unsigned int CNcbiTable<TValue, TRow, TColumn>::Cols() const
247 {
248     return m_Cols;
249 }
250 
251 template<class TValue, class TRow, class TColumn>
AddColumn(const TColumn & col)252 void CNcbiTable<TValue, TRow, TColumn>::AddColumn(const TColumn& col)
253 {
254     unsigned int cidx = m_Cols;
255     AssociateColumn(col, cidx);
256     NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
257         TRowType* r = *it;
258         r->push_back(TValue());
259     }
260     ++m_Cols;
261 }
262 
263 template<class TValue, class TRow, class TColumn>
AddRow(const TRow & row)264 void CNcbiTable<TValue, TRow, TColumn>::AddRow(const TRow& row)
265 {
266     unsigned int ridx = m_Rows;
267     TRowType* r = new TRowType(m_Cols);
268     m_Table.push_back(r);
269 
270     AssociateRow(row, ridx);
271     ++m_Rows;
272 }
273 
274 template<class TValue, class TRow, class TColumn>
AssociateRow(const TRow & row,unsigned int row_idx)275 void CNcbiTable<TValue, TRow, TColumn>::AssociateRow(const TRow&  row,
276                                                      unsigned int row_idx)
277 {
278     typename TRowMap::const_iterator it = m_RowMap.find(row);
279     if (it == m_RowMap.end()) {
280         m_RowMap.insert(pair<TRow, unsigned int>(row, row_idx));
281     } else {
282         NCBI_THROW(
283           CNcbiTable_Exception,
284           eRowAlreadyExists, "Cannot assign row key (already assigned).");
285     }
286 }
287 
288 template<class TValue, class TRow, class TColumn>
AssociateColumn(const TColumn & col,unsigned int col_idx)289 void CNcbiTable<TValue, TRow, TColumn>::AssociateColumn(const TColumn& col,
290                                                         unsigned int   col_idx)
291 {
292     typename TColumnMap::const_iterator it = m_ColumnMap.find(col);
293     if (it == m_ColumnMap.end()) {
294         m_ColumnMap.insert(pair<TColumn, unsigned int>(col, col_idx));
295     } else {
296         NCBI_THROW(
297           CNcbiTable_Exception,
298           eRowAlreadyExists, "Cannot assign column key (already assigned).");
299     }
300 
301 }
302 
303 template<class TValue, class TRow, class TColumn>
Resize(unsigned int rows,unsigned int cols)304 void CNcbiTable<TValue, TRow, TColumn>::Resize(unsigned int rows,
305                                                unsigned int cols)
306 {
307     m_Rows = rows;
308 
309     if (rows < m_Rows) {
310         m_Table.resize(rows);
311         if (m_Cols == cols)
312             return; // nothing to do
313     } else {
314         m_Table.resize(rows, 0);
315     }
316     m_Cols = cols;
317 
318     NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
319         TRowType* r = *it;
320         if (r == 0) {  // new row
321             r = new TRowType();
322             r->resize(cols);
323             *it = r;
324         } else {
325             if (r->size() != cols) { // resize required
326                 r->resize(cols);
327             }
328         }
329     }
330 }
331 
332 template<class TValue, class TRow, class TColumn>
Resize(unsigned int rows,unsigned int cols,const TValue & v)333 void CNcbiTable<TValue, TRow, TColumn>::Resize(unsigned int  rows,
334                                                unsigned int  cols,
335                                                const TValue& v)
336 {
337     m_Rows = rows;
338 
339     if (rows < m_Rows) {
340         m_Table.resize(rows);
341         if (m_Cols == cols)
342             return; // nothing to do
343     } else {
344         m_Table.resize(rows, 0);
345     }
346     m_Cols = cols;
347 
348     NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
349         TRowType* r = *it;
350         if (r == 0) {  // new row
351             r = new TRowType();
352             r->resize(cols, v);
353             *it = r;
354         } else {
355             if (r->size() != cols) { // resize required
356                 r->resize(cols, v);
357             }
358         }
359     }
360 }
361 
362 
363 template<class TValue, class TRow, class TColumn>
364 const typename CNcbiTable<TValue, TRow, TColumn>::TRowType&
GetRow(const TRow & row) const365 CNcbiTable<TValue, TRow, TColumn>::GetRow(const TRow& row) const
366 {
367     typename TRowMap::const_iterator it = m_RowMap.find(row);
368     if (it == m_RowMap.end()) {
369         NCBI_THROW(
370           CNcbiTable_Exception,
371           eRowNotFound, "Row not found.");
372     }
373     unsigned int idx = it->second;
374     return *(m_Table[idx]);
375 }
376 
377 template<class TValue, class TRow, class TColumn>
378 const typename CNcbiTable<TValue, TRow, TColumn>::TRowType&
GetRowVector(unsigned int row_idx) const379 CNcbiTable<TValue, TRow, TColumn>::GetRowVector(unsigned int row_idx) const
380 {
381     return *(m_Table[row_idx]);
382 }
383 
384 template<class TValue, class TRow, class TColumn>
385 typename CNcbiTable<TValue, TRow, TColumn>::TRowType&
GetRowVector(unsigned int row_idx)386 CNcbiTable<TValue, TRow, TColumn>::GetRowVector(unsigned int row_idx)
387 {
388     return *(m_Table[row_idx]);
389 }
390 
391 
392 template<class TValue, class TRow, class TColumn>
393 const typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetElement(const TRow & row,const TColumn & col) const394 CNcbiTable<TValue, TRow, TColumn>::GetElement(const TRow& row, const TColumn& col) const
395 {
396     unsigned int ridx = RowIdx(row);
397     unsigned int cidx = ColumnIdx(col);
398 
399     return GetCell(ridx, cidx);
400 }
401 
402 template<class TValue, class TRow, class TColumn>
403 typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetElement(const TRow & row,const TColumn & col)404 CNcbiTable<TValue, TRow, TColumn>::GetElement(const TRow& row, const TColumn& col)
405 {
406     unsigned int ridx = RowIdx(row);
407     unsigned int cidx = ColumnIdx(col);
408 
409     return GetCell(ridx, cidx);
410 }
411 
412 
413 template<class TValue, class TRow, class TColumn>
414 unsigned int
ColumnIdx(const TColumn & col) const415 CNcbiTable<TValue, TRow, TColumn>::ColumnIdx(const TColumn& col) const
416 {
417     typename TColumnMap::const_iterator it = m_ColumnMap.find(col);
418     if (it == m_ColumnMap.end()) {
419         NCBI_THROW(
420           CNcbiTable_Exception,
421           eColumnNotFound, "Column not found.");
422     }
423     return it->second;
424 }
425 
426 template<class TValue, class TRow, class TColumn>
427 unsigned int
RowIdx(const TRow & row) const428 CNcbiTable<TValue, TRow, TColumn>::RowIdx(const TRow& row) const
429 {
430     typename TRowMap::const_iterator it = m_RowMap.find(row);
431     if (it == m_RowMap.end()) {
432         NCBI_THROW(
433           CNcbiTable_Exception,
434           eRowNotFound, "Row not found.");
435     }
436     return it->second;
437 }
438 
439 template<class TValue, class TRow, class TColumn>
440 const TColumn&
Column(unsigned int idx) const441 CNcbiTable<TValue, TRow, TColumn>::Column(unsigned int idx) const
442 {
443     typename TColumnMap::const_iterator it = m_ColumnMap.begin();
444     for(it=m_ColumnMap.begin(); it!=m_ColumnMap.end(); ++it) {
445         if ( (*it).second == idx )
446             return (*it).first;
447     }
448 
449     NCBI_THROW(CNcbiTable_Exception, eColumnNotFound, "Column not found.");
450 }
451 
452 template<class TValue, class TRow, class TColumn>
453 const TRow&
Row(unsigned int idx) const454 CNcbiTable<TValue, TRow, TColumn>::Row(unsigned int idx) const
455 {
456     typename TRowMap::const_iterator it = m_RowMap.begin();
457     for(it=m_RowMap.begin(); it!=m_RowMap.end(); ++it) {
458         if ( (*it).second == idx )
459             return (*it).first;
460     }
461 
462     NCBI_THROW(CNcbiTable_Exception, eRowNotFound, "Row not found.");
463 }
464 
465 template<class TValue, class TRow, class TColumn>
466 const typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetCell(unsigned int row_idx,unsigned int col_idx) const467 CNcbiTable<TValue, TRow, TColumn>::GetCell(unsigned int row_idx,
468                                            unsigned int col_idx) const
469 {
470     const TRowType& r = *(m_Table[row_idx]);
471     return r[col_idx];
472 }
473 
474 template<class TValue, class TRow, class TColumn>
475 typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetCell(unsigned int row_idx,unsigned int col_idx)476 CNcbiTable<TValue, TRow, TColumn>::GetCell(unsigned int row_idx,
477                                            unsigned int col_idx)
478 {
479     TRowType& r = *(m_Table[row_idx]);
480     return r[col_idx];
481 }
482 
483 
484 END_NCBI_SCOPE
485 
486 #endif  /* UTIL_NCBITABLE__HPP */
487