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