recordtmpl.h

Go to the documentation of this file.
00001 ///
00002 /// \file       recordtmpl.h
00003 ///             Standalone templates related to the record classes.
00004 ///             Split into a separate file to speed compile times.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #ifndef __BARRY_RECORD_TEMPLATES_H__
00024 #define __BARRY_RECORD_TEMPLATES_H__
00025 
00026 #include "dll.h"
00027 #include <iosfwd>
00028 #include <iostream>
00029 #include <sstream>
00030 
00031 namespace Barry {
00032 
00033 //////////////////////////////////////////////////////////////////////////////
00034 // Generic Field Handles
00035 
00036 /// \addtogroup GenericFieldHandles
00037 /// @{
00038 
00039 //////////////////////////////////////////////////////////////////////////////
00040 // *NamedFieldCmp classes
00041 
00042 /// FieldSorter<> is a helper class for NamedFieldCmp<>, used as the
00043 /// callback for FieldHandle<>::Member().  It uses operator< to store
00044 /// a comparison result for the given record and field.
00045 template <class RecordT>
00046 class FieldSorter
00047 {
00048         const RecordT &m_one, &m_two;
00049         mutable bool m_comparison, m_equal;
00050 
00051 public:
00052         FieldSorter(const RecordT &a, const RecordT &b)
00053                 : m_one(a)
00054                 , m_two(b)
00055                 , m_comparison(false)
00056                 , m_equal(false)
00057         {
00058         }
00059 
00060         bool GetComparison() const { return m_comparison; }
00061         bool IsEqual() const { return m_equal; }
00062 
00063         void operator()(EnumFieldBase<RecordT> *ep,
00064                 const FieldIdentity &id) const
00065         {
00066                 m_comparison = ep->GetValue(m_one) < ep->GetValue(m_two);
00067                 m_equal = !m_comparison &&
00068                         !(ep->GetValue(m_two) < ep->GetValue(m_one));
00069         }
00070 
00071         void operator()(typename FieldHandle<RecordT>::PostalPointer pp,
00072                 const FieldIdentity &id) const
00073         {
00074                 const std::string
00075                         &a = m_one.*(pp.m_PostalAddress).*(pp.m_PostalField),
00076                         &b = m_two.*(pp.m_PostalAddress).*(pp.m_PostalField);
00077 
00078                 m_comparison = a < b;
00079                 m_equal = !m_comparison && !(b < a);
00080         }
00081 
00082         template <class TypeT>
00083         void operator()(TypeT RecordT::* mp, const FieldIdentity &id) const
00084         {
00085                 m_comparison = m_one.*mp < m_two.*mp;
00086                 m_equal = !m_comparison && !(m_two.*mp < m_one.*mp);
00087         }
00088 };
00089 
00090 //
00091 // NamedFieldCmp<>
00092 //
00093 /// A comparison functor, intended to be used in std::sort(), which
00094 /// allows sorting by a particular record's member variable, selected
00095 /// by string name.  eg. It allows you to sort a vector of Contact
00096 /// records by Name, HomeAddress, WorkPhone, or Company name, etc.
00097 ///
00098 /// This template takes the record type as template argument, and works
00099 /// with only that record type.
00100 ///
00101 /// If the given name is not found the FieldHandles for RecordT, this
00102 /// class will throw a std::logic_error exception.
00103 ///
00104 template <class RecordT>
00105 class NamedFieldCmp
00106 {
00107         const std::string &m_name;
00108 
00109 public:
00110         NamedFieldCmp(const std::string &field_name)
00111                 : m_name(field_name)
00112         {
00113         }
00114 
00115         bool operator() (const RecordT &a, const RecordT &b) const
00116         {
00117                 bool comparison = false;
00118                 std::string token;
00119                 std::istringstream iss(m_name);
00120                 while( std::getline(iss, token, ',') ) {
00121                         typename FieldHandle<RecordT>::ListT::const_iterator
00122                                 fhi = RecordT::GetFieldHandles().begin(),
00123                                 fhe = RecordT::GetFieldHandles().end();
00124 
00125                         for( ; fhi != fhe; ++fhi ) {
00126                                 if( token == fhi->GetIdentity().Name ) {
00127                                         FieldSorter<RecordT> fs(a, b);
00128                                         fhi->Member(fs);
00129                                         comparison = fs.GetComparison();
00130                                         if( fs.IsEqual() ) {
00131                                                 // if equal, compare next token
00132                                                 break;
00133                                         }
00134                                         else {
00135                                                 // done!
00136                                                 return comparison;
00137                                         }
00138                                 }
00139                         }
00140 
00141                         if( fhi == fhe )
00142                                 throw std::logic_error("NamedFieldCmp: No field named '" + token + "' in '" + RecordT::GetDBName() + "'");
00143                 }
00144 
00145                 // return last seen comparison
00146                 return comparison;
00147         }
00148 };
00149 
00150 class IConverter;
00151 class DBData;
00152 
00153 //
00154 // DBNamedFieldCmp
00155 //
00156 /// This class is a wrapper around the NamedFieldCmp<>, allowing you to
00157 /// sort a vector (or other container) of DBData objects.  This class will
00158 /// parse each record before passing the result on to NamedFieldCmp<>
00159 /// and returning the result.  All the parsing work is then thrown away,
00160 /// so this is more of a convenience class than for performance.
00161 ///
00162 /// This class expects that all the DBData given to it is one of the
00163 /// known records which have a parser.  If the record unrecognized, it
00164 /// will throw a std::logic_error exception.
00165 ///
00166 class DBNamedFieldCmp
00167 {
00168         const std::string &m_name;
00169         const IConverter *m_ic;
00170 
00171 public:
00172         explicit DBNamedFieldCmp(const std::string &field_name,
00173                         const Barry::IConverter *ic = 0);
00174 
00175         bool operator() (const Barry::DBData &a, const Barry::DBData &b) const;
00176 };
00177 
00178 /// @}
00179 
00180 } // namespace Barry
00181 
00182 #endif
00183