diff --git a/field_map.go b/field_map.go index 6326a18aa..59a8a58a1 100644 --- a/field_map.go +++ b/field_map.go @@ -6,15 +6,30 @@ import ( "time" ) -//tagValues stores a slice of TagValues -type tagValues struct { +//field stores a slice of TagValues +type field struct { tvs []TagValue } -func (f *tagValues) Tag() Tag { +func (f *field) Tag() Tag { return f.tvs[0].tag } +func (f *field) init(tag Tag, value []byte) { + if len(f.tvs) == 0 { + f.tvs = make([]TagValue, 1) + } else { + f.tvs = f.tvs[:1] + } + f.tvs[0].init(tag, value) +} + +func (f *field) write(buffer *bytes.Buffer) { + for _, tv := range f.tvs { + buffer.Write(tv.bytes) + } +} + // tagOrder true if tag i should occur before tag j type tagOrder func(i, j Tag) bool @@ -29,7 +44,7 @@ func (t tagSort) Less(i, j int) bool { return t.compare(t.tags[i], t.tags[j]) } //FieldMap is a collection of fix fields that make up a fix message. type FieldMap struct { - tagLookup map[Tag]*tagValues + tagLookup map[Tag]*field tagSort } @@ -41,7 +56,7 @@ func (m *FieldMap) init() { } func (m *FieldMap) initWithOrdering(ordering tagOrder) { - m.tagLookup = make(map[Tag]*tagValues) + m.tagLookup = make(map[Tag]*field) m.compare = ordering } @@ -68,12 +83,12 @@ func (m FieldMap) Has(tag Tag) bool { //GetField parses of a field with Tag tag. Returned reject may indicate the field is not present, or the field value is invalid. func (m FieldMap) GetField(tag Tag, parser FieldValueReader) MessageRejectError { - tagValues, ok := m.tagLookup[tag] + f, ok := m.tagLookup[tag] if !ok { return ConditionallyRequiredFieldMissing(tag) } - if err := parser.Read(tagValues.tvs[0].value); err != nil { + if err := parser.Read(f.tvs[0].value); err != nil { return IncorrectDataFormatForValue(tag) } @@ -82,12 +97,12 @@ func (m FieldMap) GetField(tag Tag, parser FieldValueReader) MessageRejectError //GetBytes is a zero-copy GetField wrapper for []bytes fields func (m FieldMap) GetBytes(tag Tag) ([]byte, MessageRejectError) { - tagValues, ok := m.tagLookup[tag] + f, ok := m.tagLookup[tag] if !ok { return nil, ConditionallyRequiredFieldMissing(tag) } - return tagValues.tvs[0].value, nil + return f.tvs[0].value, nil } //GetBool is a GetField wrapper for bool fields @@ -140,12 +155,12 @@ func (m FieldMap) GetString(tag Tag) (string, MessageRejectError) { //GetGroup is a Get function specific to Group Fields. func (m FieldMap) GetGroup(parser FieldGroupReader) MessageRejectError { - tagValues, ok := m.tagLookup[parser.Tag()] + f, ok := m.tagLookup[parser.Tag()] if !ok { return ConditionallyRequiredFieldMissing(parser.Tag()) } - if _, err := parser.Read(tagValues.tvs); err != nil { + if _, err := parser.Read(f.tvs); err != nil { if msgRejErr, ok := err.(MessageRejectError); ok { return msgRejErr } @@ -157,9 +172,13 @@ func (m FieldMap) GetGroup(parser FieldGroupReader) MessageRejectError { //SetField sets the field with Tag tag func (m *FieldMap) SetField(tag Tag, field FieldValueWriter) *FieldMap { - tValues := m.getOrCreate(tag) - tValues.tvs = make([]TagValue, 1) - tValues.tvs[0].init(tag, field.Write()) + return m.SetBytes(tag, field.Write()) +} + +//SetBytes sets bytes +func (m *FieldMap) SetBytes(tag Tag, value []byte) *FieldMap { + f := m.getOrCreate(tag) + f.init(tag, value) return m } @@ -170,12 +189,13 @@ func (m *FieldMap) SetBool(tag Tag, value bool) *FieldMap { //SetInt is a SetField wrapper for int fields func (m *FieldMap) SetInt(tag Tag, value int) *FieldMap { - return m.SetField(tag, FIXInt(value)) + v := FIXInt(value) + return m.SetBytes(tag, v.Write()) } //SetString is a SetField wrapper for string fields func (m *FieldMap) SetString(tag Tag, value string) *FieldMap { - return m.SetField(tag, FIXString(value)) + return m.SetBytes(tag, []byte(value)) } //Clear purges all fields from field map @@ -186,7 +206,7 @@ func (m *FieldMap) Clear() { } } -func (m *FieldMap) add(f *tagValues) { +func (m *FieldMap) add(f *field) { if _, ok := m.tagLookup[f.Tag()]; !ok { m.tags = append(m.tags, f.Tag()) } @@ -194,12 +214,12 @@ func (m *FieldMap) add(f *tagValues) { m.tagLookup[f.Tag()] = f } -func (m *FieldMap) getOrCreate(tag Tag) *tagValues { +func (m *FieldMap) getOrCreate(tag Tag) *field { if f, ok := m.tagLookup[tag]; ok { return f } - f := new(tagValues) + f := new(field) m.tagLookup[tag] = f m.tags = append(m.tags, tag) return f @@ -207,10 +227,8 @@ func (m *FieldMap) getOrCreate(tag Tag) *tagValues { //Set is a setter for fields func (m *FieldMap) Set(field FieldWriter) *FieldMap { - tValues := m.getOrCreate(field.Tag()) - tValues.tvs = make([]TagValue, 1) - tValues.tvs[0].init(field.Tag(), field.Write()) - m.tagLookup[field.Tag()] = tValues + f := m.getOrCreate(field.Tag()) + f.init(field.Tag(), field.Write()) return m } @@ -228,10 +246,8 @@ func (m *FieldMap) sortedTags() []Tag { func (m FieldMap) write(buffer *bytes.Buffer) { for _, tag := range m.sortedTags() { - if fields, ok := m.tagLookup[tag]; ok { - for _, tv := range fields.tvs { - buffer.Write(tv.bytes) - } + if f, ok := m.tagLookup[tag]; ok { + f.write(buffer) } } } diff --git a/fix_int.go b/fix_int.go index 3185d6d35..b3695116e 100644 --- a/fix_int.go +++ b/fix_int.go @@ -59,5 +59,5 @@ func (f *FIXInt) Read(bytes []byte) error { } func (f FIXInt) Write() []byte { - return []byte(strconv.Itoa(int(f))) + return strconv.AppendInt(nil, int64(f), 10) } diff --git a/message.go b/message.go index 7b3151a18..61fc1021b 100644 --- a/message.go +++ b/message.go @@ -144,7 +144,7 @@ func ParseMessage(msg *Message, rawMessage *bytes.Buffer) (err error) { return } - msg.Header.add(&tagValues{msg.fields[fieldIndex : fieldIndex+1]}) + msg.Header.add(&field{msg.fields[fieldIndex : fieldIndex+1]}) fieldIndex++ parsedFieldBytes := &msg.fields[fieldIndex] @@ -152,7 +152,7 @@ func ParseMessage(msg *Message, rawMessage *bytes.Buffer) (err error) { return } - msg.Header.add(&tagValues{msg.fields[fieldIndex : fieldIndex+1]}) + msg.Header.add(&field{msg.fields[fieldIndex : fieldIndex+1]}) fieldIndex++ parsedFieldBytes = &msg.fields[fieldIndex] @@ -160,7 +160,7 @@ func ParseMessage(msg *Message, rawMessage *bytes.Buffer) (err error) { return } - msg.Header.add(&tagValues{msg.fields[fieldIndex : fieldIndex+1]}) + msg.Header.add(&field{msg.fields[fieldIndex : fieldIndex+1]}) fieldIndex++ trailerBytes := []byte{} @@ -174,13 +174,13 @@ func ParseMessage(msg *Message, rawMessage *bytes.Buffer) (err error) { switch { case parsedFieldBytes.tag.IsHeader(): - msg.Header.add(&tagValues{msg.fields[fieldIndex : fieldIndex+1]}) + msg.Header.add(&field{msg.fields[fieldIndex : fieldIndex+1]}) case parsedFieldBytes.tag.IsTrailer(): - msg.Trailer.add(&tagValues{msg.fields[fieldIndex : fieldIndex+1]}) + msg.Trailer.add(&field{msg.fields[fieldIndex : fieldIndex+1]}) default: foundBody = true trailerBytes = rawBytes - msg.Body.add(&tagValues{msg.fields[fieldIndex : fieldIndex+1]}) + msg.Body.add(&field{msg.fields[fieldIndex : fieldIndex+1]}) } if parsedFieldBytes.tag == tagCheckSum { break @@ -305,8 +305,8 @@ func (m *Message) String() string { return string(m.build()) } -func newCheckSum(value int) FIXString { - return FIXString(fmt.Sprintf("%03d", value)) +func formatCheckSum(value int) string { + return fmt.Sprintf("%03d", value) } //Build constructs a []byte from a Message instance @@ -322,7 +322,7 @@ func (m *Message) build() []byte { func (m *Message) cook() { bodyLength := m.Header.length() + m.Body.length() + m.Trailer.length() - m.Header.SetField(tagBodyLength, FIXInt(bodyLength)) + m.Header.SetInt(tagBodyLength, bodyLength) checkSum := (m.Header.total() + m.Body.total() + m.Trailer.total()) % 256 - m.Trailer.SetField(tagCheckSum, newCheckSum(checkSum)) + m.Trailer.SetString(tagCheckSum, formatCheckSum(checkSum)) } diff --git a/repeating_group.go b/repeating_group.go index 5f9f726ed..4aba34c73 100644 --- a/repeating_group.go +++ b/repeating_group.go @@ -182,24 +182,24 @@ func (f *RepeatingGroup) Read(tv []TagValue) ([]TagValue, error) { group := new(Group) group.initWithOrdering(tagOrdering) for len(tv) > 0 { - field, ok := f.findItemInGroupTemplate(tv[0].tag) + gi, ok := f.findItemInGroupTemplate(tv[0].tag) if !ok { break } tvRange := tv - if tv, err = field.Read(tv); err != nil { + if tv, err = gi.Read(tv); err != nil { return tv, err } - if f.isDelimiter(field.Tag()) { + if f.isDelimiter(gi.Tag()) { group = new(Group) group.initWithOrdering(tagOrdering) f.groups = append(f.groups, group) } - group.tagLookup[tvRange[0].tag] = &tagValues{tvRange} + group.tagLookup[tvRange[0].tag] = &field{tvRange} } if len(f.groups) != expectedGroupSize { diff --git a/session.go b/session.go index 7886d1e07..2be5d3997 100644 --- a/session.go +++ b/session.go @@ -99,22 +99,21 @@ func (s *session) insertSendingTime(msg *Message) { } } -func optionallySetID(header Header, field Tag, value string) { +func optionallySetID(msg *Message, field Tag, value string) { if len(value) != 0 { - header.SetString(field, value) + msg.Header.SetString(field, value) } } func (s *session) fillDefaultHeader(msg *Message, inReplyTo *Message) { - msg.Header.SetField(tagBeginString, FIXString(s.sessionID.BeginString)) - - msg.Header.SetField(tagSenderCompID, FIXString(s.sessionID.SenderCompID)) - optionallySetID(msg.Header, tagSenderSubID, s.sessionID.SenderSubID) - optionallySetID(msg.Header, tagSenderLocationID, s.sessionID.SenderLocationID) - - msg.Header.SetField(tagTargetCompID, FIXString(s.sessionID.TargetCompID)) - optionallySetID(msg.Header, tagTargetSubID, s.sessionID.TargetSubID) - optionallySetID(msg.Header, tagTargetLocationID, s.sessionID.TargetLocationID) + msg.Header.SetString(tagBeginString, s.sessionID.BeginString) + msg.Header.SetString(tagSenderCompID, s.sessionID.SenderCompID) + optionallySetID(msg, tagSenderSubID, s.sessionID.SenderSubID) + optionallySetID(msg, tagSenderLocationID, s.sessionID.SenderLocationID) + + msg.Header.SetString(tagTargetCompID, s.sessionID.TargetCompID) + optionallySetID(msg, tagTargetSubID, s.sessionID.TargetSubID) + optionallySetID(msg, tagTargetLocationID, s.sessionID.TargetLocationID) s.insertSendingTime(msg) diff --git a/tag_value.go b/tag_value.go index ab5010e80..86e330509 100644 --- a/tag_value.go +++ b/tag_value.go @@ -14,14 +14,12 @@ type TagValue struct { } func (tv *TagValue) init(tag Tag, value []byte) { - var buf bytes.Buffer - buf.WriteString(strconv.Itoa(int(tag))) - buf.WriteString("=") - buf.Write(value) - buf.WriteString("") + tv.bytes = strconv.AppendInt(nil, int64(tag), 10) + tv.bytes = append(tv.bytes, []byte("=")...) + tv.bytes = append(tv.bytes, value...) + tv.bytes = append(tv.bytes, []byte("")...) tv.tag = tag - tv.bytes = buf.Bytes() tv.value = value } @@ -41,8 +39,9 @@ func (tv *TagValue) parse(rawFieldBytes []byte) (err error) { } tv.tag = Tag(parsedTag) - tv.value = rawFieldBytes[(sepIndex + 1):(len(rawFieldBytes) - 1)] - tv.bytes = rawFieldBytes + n := len(rawFieldBytes) + tv.value = rawFieldBytes[(sepIndex + 1):(n - 1):(n - 1)] + tv.bytes = rawFieldBytes[:n:n] return }