1 /* -*- C++ -*- */ 2 3 /**************************************************************************** 4 ** Copyright (c) 2001-2014 5 ** 6 ** This file is part of the QuickFIX FIX Engine 7 ** 8 ** This file may be distributed under the terms of the quickfixengine.org 9 ** license as defined by quickfixengine.org and appearing in the file 10 ** LICENSE included in the packaging of this file. 11 ** 12 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 ** 15 ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 ** 17 ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 ** not clear to you. 19 ** 20 ****************************************************************************/ 21 22 #ifndef FIX_FIELDMAP 23 #define FIX_FIELDMAP 24 25 #ifdef _MSC_VER 26 #pragma warning( disable: 4786 ) 27 #endif 28 29 #include "Field.h" 30 #include "MessageSorters.h" 31 #include "Exceptions.h" 32 #include "Utility.h" 33 #include <map> 34 #include <vector> 35 #include <sstream> 36 #include <algorithm> 37 38 namespace FIX 39 { 40 /** 41 * Stores and organizes a collection of Fields. 42 * 43 * This is the basis for a message, header, and trailer. This collection 44 * class uses a sorter to keep the fields in a particular order. 45 */ 46 class FieldMap 47 { 48 49 class sorter 50 { 51 public: sorter(const message_order & order)52 explicit sorter( const message_order& order ) : m_order( order ) {} 53 operator()54 bool operator()( int tag, const FieldBase& right ) const 55 { 56 return m_order( tag, right.getTag() ); 57 } 58 operator()59 bool operator()( const FieldBase& left, int tag ) const 60 { 61 return m_order( left.getTag(), tag ); 62 } 63 operator()64 bool operator()( const FieldBase& left, const FieldBase& right ) const 65 { 66 return m_order( left.getTag(), right.getTag() ); 67 } 68 69 private: 70 const message_order& m_order; 71 }; 72 73 class finder 74 { 75 public: finder(int tag)76 explicit finder( int tag ) : m_tag( tag ) {} 77 operator()78 bool operator()( const FieldBase& field ) const 79 { 80 return m_tag == field.getTag(); 81 } 82 83 private: 84 int m_tag; 85 }; 86 87 enum { DEFAULT_SIZE = 16 }; 88 89 protected: 90 91 FieldMap( const message_order& order, int size ); 92 93 public: 94 95 typedef std::vector < FieldBase, ALLOCATOR< FieldBase > > Fields; 96 typedef std::map < int, std::vector < FieldMap* >, std::less<int>, 97 ALLOCATOR<std::pair<const int, std::vector< FieldMap* > > > > Groups; 98 99 typedef Fields::iterator iterator; 100 typedef Fields::const_iterator const_iterator; 101 typedef Groups::iterator g_iterator; 102 typedef Groups::const_iterator g_const_iterator; 103 104 FieldMap( const message_order& order = 105 message_order( message_order::normal ) ); 106 107 FieldMap( const int order[] ); 108 109 FieldMap( const FieldMap& copy ); 110 111 virtual ~FieldMap(); 112 113 FieldMap& operator=( const FieldMap& rhs ); 114 115 /// Set a field without type checking 116 void setField( const FieldBase& field, bool overwrite = true ) throw(RepeatedTag)117 throw( RepeatedTag ) 118 { 119 if( !overwrite ) 120 { 121 addField( field ); 122 } 123 else 124 { 125 Fields::iterator i = findTag( field.getTag() ); 126 if( i == m_fields.end() ) 127 { 128 addField( field ); 129 } 130 else 131 { 132 i->setString( field.getString() ); 133 } 134 } 135 } 136 137 /// Set a field without a field class setField(int tag,const std::string & value)138 void setField( int tag, const std::string& value ) 139 throw( RepeatedTag, NoTagValue ) 140 { 141 FieldBase fieldBase( tag, value ); 142 setField( fieldBase ); 143 } 144 145 /// Get a field if set getFieldIfSet(FieldBase & field)146 bool getFieldIfSet( FieldBase& field ) const 147 { 148 Fields::const_iterator iter = findTag( field.getTag() ); 149 if ( iter == m_fields.end() ) 150 return false; 151 field = (*iter); 152 return true; 153 } 154 155 /// Get a field without type checking getField(FieldBase & field)156 FieldBase& getField( FieldBase& field ) 157 const throw( FieldNotFound ) 158 { 159 field = getFieldRef( field.getTag() ); 160 return field; 161 } 162 163 /// Get a field without a field class getField(int tag)164 const std::string& getField( int tag ) 165 const throw( FieldNotFound ) 166 { 167 return getFieldRef( tag ).getString(); 168 } 169 170 /// Get direct access to a field through a reference getFieldRef(int tag)171 const FieldBase& getFieldRef( int tag ) 172 const throw( FieldNotFound ) 173 { 174 Fields::const_iterator iter = findTag( tag ); 175 if ( iter == m_fields.end() ) 176 throw FieldNotFound( tag ); 177 return (*iter); 178 } 179 180 /// Get direct access to a field through a pointer getFieldPtr(int tag)181 const FieldBase* const getFieldPtr( int tag ) 182 const throw( FieldNotFound ) 183 { 184 return &getFieldRef( tag ); 185 } 186 187 /// Check to see if a field is set isSetField(const FieldBase & field)188 bool isSetField( const FieldBase& field ) const 189 { return isSetField( field.getTag() ); } 190 /// Check to see if a field is set by referencing its number isSetField(int tag)191 bool isSetField( int tag ) const 192 { return findTag( tag ) != m_fields.end(); } 193 194 /// Remove a field. If field is not present, this is a no-op. 195 void removeField( int tag ); 196 197 /// Add a group. 198 void addGroup( int tag, const FieldMap& group, bool setCount = true ); 199 200 /// Acquire ownership of Group object 201 void addGroupPtr( int tag, FieldMap * group, bool setCount = true ); 202 203 /// Replace a specific instance of a group. 204 void replaceGroup( int num, int tag, const FieldMap& group ); 205 206 /// Get a specific instance of a group. getGroup(int num,int tag,FieldMap & group)207 FieldMap& getGroup( int num, int tag, FieldMap& group ) const 208 throw( FieldNotFound ) 209 { 210 return group = getGroupRef( num, tag ); 211 } 212 213 /// Get direct access to a field through a reference getGroupRef(int num,int tag)214 FieldMap& getGroupRef( int num, int tag ) const 215 throw( FieldNotFound ) 216 { 217 Groups::const_iterator i = m_groups.find( tag ); 218 if( i == m_groups.end() ) throw FieldNotFound( tag ); 219 if( num <= 0 ) throw FieldNotFound( tag ); 220 if( i->second.size() < (unsigned)num ) throw FieldNotFound( tag ); 221 return *( *(i->second.begin() + (num-1) ) ); 222 } 223 224 /// Get direct access to a field through a pointer getGroupPtr(int num,int tag)225 FieldMap* getGroupPtr( int num, int tag ) const 226 throw( FieldNotFound ) 227 { 228 return &getGroupRef( num, tag ); 229 } 230 231 /// Remove a specific instance of a group. 232 void removeGroup( int num, int tag ); 233 /// Remove all instances of a group. 234 void removeGroup( int tag ); 235 236 /// Check to see any instance of a group exists 237 bool hasGroup( int tag ) const; 238 /// Check to see if a specific instance of a group exists 239 bool hasGroup( int num, int tag ) const; 240 /// Count the number of instance of a group 241 size_t groupCount( int tag ) const; 242 243 /// Clear all fields from the map 244 void clear(); 245 /// Check if map contains any fields 246 bool isEmpty(); 247 248 size_t totalFields() const; 249 250 std::string& calculateString( std::string& ) const; 251 252 int calculateLength( int beginStringField = FIELD::BeginString, 253 int bodyLengthField = FIELD::BodyLength, 254 int checkSumField = FIELD::CheckSum ) const; 255 256 int calculateTotal( int checkSumField = FIELD::CheckSum ) const; 257 begin()258 iterator begin() { return m_fields.begin(); } end()259 iterator end() { return m_fields.end(); } begin()260 const_iterator begin() const { return m_fields.begin(); } end()261 const_iterator end() const { return m_fields.end(); } g_begin()262 g_iterator g_begin() { return m_groups.begin(); } g_end()263 g_iterator g_end() { return m_groups.end(); } g_begin()264 g_const_iterator g_begin() const { return m_groups.begin(); } g_end()265 g_const_iterator g_end() const { return m_groups.end(); } 266 267 protected: 268 269 friend class Message; 270 addField(const FieldBase & field)271 void addField( const FieldBase& field ) 272 { 273 Fields::iterator iter = findPositionFor( field.getTag() ); 274 if( iter == m_fields.end() ) 275 { 276 m_fields.push_back( field ); 277 } 278 else 279 { 280 m_fields.insert( iter, field ); 281 } 282 } 283 284 // used to find data length fields during message decoding 285 // message fields are not yet sorted so regular find*** functions might return wrong results reverse_find(int tag)286 const FieldBase& reverse_find( int tag ) const 287 { 288 Fields::const_reverse_iterator iter = std::find_if( m_fields.rbegin(), m_fields.rend(), finder( tag ) ); 289 if( iter == m_fields.rend() ) 290 throw FieldNotFound( tag ); 291 292 return *iter; 293 } 294 295 // append field to message without sorting 296 // only applicable during message decoding appendField(const FieldBase & field)297 void appendField( const FieldBase& field ) 298 { 299 m_fields.push_back( field ); 300 } 301 302 // sort fields after message decoding sortFields()303 void sortFields() 304 { 305 std::sort( m_fields.begin(), m_fields.end(), sorter(m_order) ); 306 } 307 308 private: 309 findTag(int tag)310 Fields::const_iterator findTag( int tag ) const 311 { 312 return lookup( m_fields.begin(), m_fields.end(), tag ); 313 } 314 findTag(int tag)315 Fields::iterator findTag( int tag ) 316 { 317 return lookup( m_fields.begin(), m_fields.end(), tag ); 318 } 319 320 template <typename Iterator> lookup(Iterator begin,Iterator end,int tag)321 Iterator lookup(Iterator begin, Iterator end, int tag) const 322 { 323 #if defined(__SUNPRO_CC) 324 std::size_t numElements; 325 std::distance( begin, end, numElements ); 326 #else 327 std::size_t numElements = std::distance( begin, end ); 328 #endif 329 if( numElements < 16 ) 330 return std::find_if( begin, end, finder( tag ) ); 331 332 Iterator iter = std::lower_bound( begin, end, tag, sorter( m_order ) ); 333 if( iter != end && 334 iter->getTag() == tag ) 335 { 336 return iter; 337 } 338 339 return end; 340 } 341 findPositionFor(int tag)342 Fields::iterator findPositionFor( int tag ) 343 { 344 if( m_fields.empty() ) 345 return m_fields.end(); 346 347 const FieldBase& last = m_fields.back(); 348 if( m_order( last.getTag(), tag ) || 349 last.getTag() == tag ) 350 { 351 return m_fields.end(); 352 } 353 354 return std::upper_bound( m_fields.begin(), m_fields.end(), tag, sorter( m_order ) ); 355 } 356 357 Fields m_fields; 358 Groups m_groups; 359 message_order m_order; 360 }; 361 /*! @} */ 362 } 363 364 #define FIELD_SET( MAP, FIELD ) \ 365 bool isSet( const FIELD& field ) const \ 366 { return (MAP).isSetField(field); } \ 367 void set( const FIELD& field ) \ 368 { (MAP).setField(field); } \ 369 FIELD& get( FIELD& field ) const \ 370 { return (FIELD&)(MAP).getField(field); } \ 371 bool getIfSet( FIELD& field ) const \ 372 { return (MAP).getFieldIfSet(field); } 373 374 #define FIELD_GET_PTR( MAP, FLD ) \ 375 (const FIX::FLD*)MAP.getFieldPtr( FIX::FIELD::FLD ) 376 #define FIELD_GET_REF( MAP, FLD ) \ 377 (const FIX::FLD&)MAP.getFieldRef( FIX::FIELD::FLD ) 378 #define FIELD_THROW_IF_NOT_FOUND( MAP, FLD ) \ 379 if( !(MAP).isSetField( FIX::FIELD::FLD) ) \ 380 throw FieldNotFound( FIX::FIELD::FLD ) 381 #endif //FIX_FIELDMAP 382 383