#ifndef FIX_FIELDMAP
#define FIX_FIELDMAP
#ifdef _MSC_VER
#pragma warning(disable : 4786)
#endif
#include "Exceptions.h"
#include "Field.h"
#include "MessageSorters.h"
#include "Utility.h"
#include <algorithm>
#include <map>
#include <sstream>
#include <vector>
namespace FIX {
class FieldMap {
class sorter {
public:
explicit sorter(const message_order &order)
: m_order(order) {}
bool operator()(int tag, const FieldBase &right) const { return m_order(tag, right.getTag()); }
bool operator()(const FieldBase &left, int tag) const { return m_order(left.getTag(), tag); }
bool operator()(const FieldBase &left, const FieldBase &right) const {
return m_order(left.getTag(), right.getTag());
}
private:
const message_order &m_order;
};
class finder {
public:
explicit finder(int tag)
: m_tag(tag) {}
bool operator()(const FieldBase &field) const { return m_tag == field.getTag(); }
private:
int m_tag;
};
enum {
DEFAULT_SIZE = 16
};
protected:
FieldMap(const message_order &order, int size);
public:
typedef std::vector<FieldBase, ALLOCATOR<FieldBase>> Fields;
typedef std::
map<int, std::vector<FieldMap *>, std::less<int>, ALLOCATOR<std::pair<const int, std::vector<FieldMap *>>>>
Groups;
typedef Fields::iterator iterator;
typedef Fields::const_iterator const_iterator;
typedef Fields::value_type value_type;
typedef Groups::iterator g_iterator;
typedef Groups::const_iterator g_const_iterator;
typedef Groups::value_type g_value_type;
FieldMap(const message_order &order = message_order(message_order::normal));
FieldMap(const int order[]);
FieldMap(const FieldMap ©);
FieldMap(FieldMap &&rhs);
virtual ~FieldMap();
FieldMap &operator=(const FieldMap &rhs);
FieldMap &operator=(FieldMap &&rhs);
void setField(const FieldBase &field, bool overwrite = true) EXCEPT(RepeatedTag) {
if (!overwrite) {
addField(field);
} else {
Fields::iterator foundField = findTag(field.getTag());
if (foundField == m_fields.end()) {
addField(field);
} else {
foundField->setString(field.getString());
}
}
}
void setField(int tag, const std::string &value) EXCEPT(RepeatedTag, NoTagValue) {
FieldBase fieldBase(tag, value);
setField(fieldBase);
}
bool getFieldIfSet(FieldBase &field) const {
Fields::const_iterator foundField = findTag(field.getTag());
if (foundField == m_fields.end()) {
return false;
}
field = (*foundField);
return true;
}
FieldBase &getField(FieldBase &field) const EXCEPT(FieldNotFound) {
field = getFieldRef(field.getTag());
return field;
}
template <typename T> const T &getField() const EXCEPT(FieldNotFound) {
return *reinterpret_cast<const T *>(&getFieldRef(T::tag));
}
const std::string &getField(int tag) const EXCEPT(FieldNotFound) { return getFieldRef(tag).getString(); }
const FieldBase &getFieldRef(int tag) const EXCEPT(FieldNotFound) {
Fields::const_iterator field = findTag(tag);
if (field == m_fields.end()) {
throw FieldNotFound(tag);
}
return (*field);
}
const FieldBase *const getFieldPtr(int tag) const EXCEPT(FieldNotFound) { return &getFieldRef(tag); }
bool isSetField(const FieldBase &field) const { return isSetField(field.getTag()); }
bool isSetField(int tag) const { return findTag(tag) != m_fields.end(); }
void removeField(int tag);
void addGroup(int tag, const FieldMap &group, bool setCount = true);
void addGroupPtr(int tag, FieldMap *group, bool setCount = true);
void replaceGroup(int num, int tag, const FieldMap &group);
FieldMap &getGroup(int num, int tag, FieldMap &group) const EXCEPT(FieldNotFound) {
return group = getGroupRef(num, tag);
}
FieldMap &getGroupRef(int num, int tag) const EXCEPT(FieldNotFound) {
Groups::const_iterator tagWithGroups = m_groups.find(tag);
if (tagWithGroups == m_groups.end()) {
throw FieldNotFound(tag);
}
if (num <= 0) {
throw FieldNotFound(tag);
}
if (tagWithGroups->second.size() < static_cast<unsigned>(num)) {
throw FieldNotFound(tag);
}
return *(*(tagWithGroups->second.begin() + (num - 1)));
}
FieldMap *getGroupPtr(int num, int tag) const EXCEPT(FieldNotFound) { return &getGroupRef(num, tag); }
const Groups &groups() const { return m_groups; }
void removeGroup(int num, int tag);
void removeGroup(int tag);
bool hasGroup(int tag) const;
bool hasGroup(int num, int tag) const;
size_t groupCount(int tag) const;
void clear();
bool isEmpty();
size_t totalFields() const;
std::string &calculateString(std::string &) const;
int calculateLength(
int beginStringField = FIELD::BeginString,
int bodyLengthField = FIELD::BodyLength,
int checkSumField = FIELD::CheckSum) const;
int calculateTotal(int checkSumField = FIELD::CheckSum) const;
iterator begin() { return m_fields.begin(); }
iterator end() { return m_fields.end(); }
const_iterator begin() const { return m_fields.begin(); }
const_iterator end() const { return m_fields.end(); }
g_iterator g_begin() { return m_groups.begin(); }
g_iterator g_end() { return m_groups.end(); }
g_const_iterator g_begin() const { return m_groups.begin(); }
g_const_iterator g_end() const { return m_groups.end(); }
protected:
friend class Message;
void addField(const FieldBase &field) {
Fields::iterator iter = findPositionFor(field.getTag());
if (iter == m_fields.end()) {
m_fields.push_back(field);
} else {
m_fields.insert(iter, field);
}
}
const FieldBase &reverse_find(int tag) const {
Fields::const_reverse_iterator field = std::find_if(m_fields.rbegin(), m_fields.rend(), finder(tag));
if (field == m_fields.rend()) {
throw FieldNotFound(tag);
}
return *field;
}
void appendField(const FieldBase &field) { m_fields.push_back(field); }
void sortFields() { std::sort(m_fields.begin(), m_fields.end(), sorter(m_order)); }
private:
Fields::const_iterator findTag(int tag) const { return lookup(m_fields.begin(), m_fields.end(), tag); }
Fields::iterator findTag(int tag) { return lookup(m_fields.begin(), m_fields.end(), tag); }
template <typename Iterator> Iterator lookup(Iterator begin, Iterator end, int tag) const {
#if defined(__SUNPRO_CC)
std::size_t numElements;
std::distance(begin, end, numElements);
#else
std::size_t numElements = std::distance(begin, end);
#endif
if (numElements < 16) {
return std::find_if(begin, end, finder(tag));
}
Iterator field = std::lower_bound(begin, end, tag, sorter(m_order));
if (field != end && field->getTag() == tag) {
return field;
}
return end;
}
Fields::iterator findPositionFor(int tag) {
if (m_fields.empty()) {
return m_fields.end();
}
const FieldBase &lastField = m_fields.back();
if (m_order(lastField.getTag(), tag) || lastField.getTag() == tag) {
return m_fields.end();
}
return std::upper_bound(m_fields.begin(), m_fields.end(), tag, sorter(m_order));
}
Fields m_fields;
Groups m_groups;
message_order m_order;
};
}
#define FIELD_SET(MAP, FIELD) \
bool isSet(const FIELD &field) const { return (MAP).isSetField(field); } \
void set(const FIELD &field) { (MAP).setField(field); } \
FIELD &get(FIELD &field) const { return (FIELD &)(MAP).getField(field); } \
bool getIfSet(FIELD &field) const { return (MAP).getFieldIfSet(field); }
#define FIELD_GET_PTR(MAP, FLD) (const FIX::FLD *)MAP.getFieldPtr(FIX::FIELD::FLD)
#define FIELD_GET_REF(MAP, FLD) (const FIX::FLD &)MAP.getFieldRef(FIX::FIELD::FLD)
#define FIELD_THROW_IF_NOT_FOUND(MAP, FLD) \
if (!(MAP).isSetField(FIX::FIELD::FLD)) \
throw FieldNotFound(FIX::FIELD::FLD)
#endif