Skip to content

Commit

Permalink
field bytes to tag value
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Busbey committed Oct 27, 2015
1 parent 43db547 commit 82998b4
Show file tree
Hide file tree
Showing 19 changed files with 270 additions and 246 deletions.
3 changes: 2 additions & 1 deletion boolean_field.go
Expand Up @@ -9,7 +9,8 @@ type BooleanValue struct {
Value bool
}

func (f *BooleanValue) Read(bytes []byte) error {
func (f *BooleanValue) Read(tv []TagValue) error {
bytes := tv[0].Value
switch string(bytes) {
case "Y":
f.Value = true
Expand Down
2 changes: 1 addition & 1 deletion boolean_field_test.go
Expand Up @@ -59,7 +59,7 @@ func TestBooleanFieldRead(t *testing.T) {

for _, test := range tests {
field := NewBooleanField(Tag(1), false)
err := field.Read(test.bytes)
err := field.Read([]TagValue{TagValue{Value: test.bytes}})

if test.expectError && err == nil {
t.Errorf("Expected error for %v", test.bytes)
Expand Down
6 changes: 5 additions & 1 deletion field.go
Expand Up @@ -3,7 +3,11 @@ package quickfix
//The FieldValue interface is used to write/extract typed field values to/from raw bytes
type FieldValue interface {
Write() []byte
Read([]byte) error

//Parameter to Read is a single length slice of TagValues. For most fields, only the first
//TagValue will be required. The capacity of the slice extends from the field to be read through the
//underlying message length. This can be useful for FieldValues made up of repeating groups.
Read([]TagValue) error
}

//Field is the interface implemented by all typed Fields in a Message
Expand Down
63 changes: 0 additions & 63 deletions field_bytes.go

This file was deleted.

90 changes: 0 additions & 90 deletions field_bytes_test.go

This file was deleted.

80 changes: 45 additions & 35 deletions field_map.go
Expand Up @@ -8,21 +8,21 @@ import (

//FieldMap is a collection of fix fields that make up a fix message.
type FieldMap struct {
fieldLookup map[Tag]*fieldBytes
fieldOrder
tagLookup map[Tag][]TagValue
tagOrder
}

// fieldOrder true if tag i should occur before tag j
type fieldOrder func(i, j Tag) bool
// tagOrder true if tag i should occur before tag j
type tagOrder func(i, j Tag) bool

type fieldSort struct {
type tagSort struct {
tags []Tag
compare fieldOrder
compare tagOrder
}

func (t fieldSort) Len() int { return len(t.tags) }
func (t fieldSort) Swap(i, j int) { t.tags[i], t.tags[j] = t.tags[j], t.tags[i] }
func (t fieldSort) Less(i, j int) bool { return t.compare(t.tags[i], t.tags[j]) }
func (t tagSort) Len() int { return len(t.tags) }
func (t tagSort) Swap(i, j int) { t.tags[i], t.tags[j] = t.tags[j], t.tags[i] }
func (t tagSort) Less(i, j int) bool { return t.compare(t.tags[i], t.tags[j]) }

//in the message header, the first 3 tags in the message header must be 8,9,35
func headerFieldOrder(i, j Tag) bool {
Expand Down Expand Up @@ -67,14 +67,14 @@ func trailerFieldOrder(i, j Tag) bool {
return i < j
}

func (m *FieldMap) init(ordering fieldOrder) {
m.fieldLookup = make(map[Tag]*fieldBytes)
m.fieldOrder = ordering
func (m *FieldMap) init(ordering tagOrder) {
m.tagLookup = make(map[Tag][]TagValue)
m.tagOrder = ordering
}

func (m FieldMap) Tags() []Tag {
tags := make([]Tag, 0, len(m.fieldLookup))
for t := range m.fieldLookup {
tags := make([]Tag, 0, len(m.tagLookup))
for t := range m.tagLookup {
tags = append(tags, t)
}

Expand All @@ -86,59 +86,67 @@ func (m FieldMap) Get(parser Field) MessageRejectError {
}

func (m FieldMap) Has(tag Tag) bool {
_, ok := m.fieldLookup[tag]
_, ok := m.tagLookup[tag]
return ok
}

func (m FieldMap) GetField(tag Tag, parser FieldValue) MessageRejectError {
field, ok := m.fieldLookup[tag]

tagValues, ok := m.tagLookup[tag]
if !ok {
return conditionallyRequiredFieldMissing(tag)
}

if err := parser.Read(field.Value); err != nil {
if err := parser.Read(tagValues[0:1]); err != nil {
return incorrectDataFormatForValue(tag)
}

return nil
}

func (m FieldMap) SetField(tag Tag, field FieldValue) {
m.fieldLookup[tag] = newFieldBytes(tag, field.Write())
tValues := make([]TagValue, 1)
tValues[0].init(tag, field.Write())
m.tagLookup[tag] = tValues
}

func (m FieldMap) Set(field Field) {
m.fieldLookup[field.Tag()] = newFieldBytes(field.Tag(), field.Write())
tValues := make([]TagValue, 1)
tValues[0].init(field.Tag(), field.Write())

m.tagLookup[field.Tag()] = tValues
}

func (m FieldMap) sortedTags() []Tag {
sortedTags := make([]Tag, len(m.fieldLookup))
for tag := range m.fieldLookup {
sortedTags := make([]Tag, len(m.tagLookup))
for tag := range m.tagLookup {
sortedTags = append(sortedTags, tag)
}

sort.Sort(fieldSort{sortedTags, m.fieldOrder})
sort.Sort(tagSort{sortedTags, m.tagOrder})
return sortedTags
}

func (m FieldMap) write(buffer *bytes.Buffer) {
tags := m.sortedTags()

for _, tag := range tags {
if field, ok := m.fieldLookup[tag]; ok {
buffer.Write(field.Data)
if fields, ok := m.tagLookup[tag]; ok {
for _, field := range fields {
buffer.Write(field.bytes)
}
}
}
}

func (m FieldMap) total() int {
total := 0
for t, field := range m.fieldLookup {
switch t {
case tagCheckSum: //tag does not contribute to total
default:
total += field.Total()
for _, fields := range m.tagLookup {
for _, field := range fields {
switch field.Tag {
case tagCheckSum: //tag does not contribute to total
default:
total += field.total()
}
}
}

Expand All @@ -147,11 +155,13 @@ func (m FieldMap) total() int {

func (m FieldMap) length() int {
length := 0
for t := range m.fieldLookup {
switch t {
case tagBeginString, tagBodyLength, tagCheckSum: //tags do not contribute to length
default:
length += m.fieldLookup[t].Length()
for _, fields := range m.tagLookup {
for _, field := range fields {
switch field.Tag {
case tagBeginString, tagBodyLength, tagCheckSum: //tags do not contribute to length
default:
length += field.length()
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion float_field.go
Expand Up @@ -11,7 +11,8 @@ type FloatValue struct {
Value float64
}

func (f *FloatValue) Read(bytes []byte) (err error) {
func (f *FloatValue) Read(tv []TagValue) (err error) {
bytes := tv[0].Value
if f.Value, err = strconv.ParseFloat(string(bytes), 64); err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion float_field_test.go
Expand Up @@ -56,7 +56,7 @@ func TestFloatFieldRead(t *testing.T) {

for _, test := range tests {
field := new(FloatField)
if err := field.Read(test.bytes); err != nil {
if err := field.Read([]TagValue{TagValue{Value: test.bytes}}); err != nil {
if !test.expectError {
t.Errorf("UnExpected '%v'", err)
}
Expand Down
16 changes: 8 additions & 8 deletions int_field.go
Expand Up @@ -14,18 +14,18 @@ const (
ascii9 = 57
)

//Atoi is similar to the function in strconv, but is tuned for ints appearing in FIX field types.
func Atoi(d []byte) (int, error) {
//atoi is similar to the function in strconv, but is tuned for ints appearing in FIX field types.
func atoi(d []byte) (int, error) {
if d[0] == asciiMinus {
n, err := ParseUInt(d[1:])
n, err := parseUInt(d[1:])
return (-1) * n, err
}

return ParseUInt(d)
return parseUInt(d)
}

//ParseUInt is similar to the function in strconv, but is tuned for ints appearing in FIX field types.
func ParseUInt(d []byte) (n int, err error) {
//parseUInt is similar to the function in strconv, but is tuned for ints appearing in FIX field types.
func parseUInt(d []byte) (n int, err error) {
if len(d) == 0 {
err = errors.New("empty bytes")
return
Expand All @@ -48,8 +48,8 @@ type IntValue struct {
Value int
}

func (f *IntValue) Read(bytes []byte) (err error) {
f.Value, err = Atoi(bytes)
func (f *IntValue) Read(tv []TagValue) (err error) {
f.Value, err = atoi(tv[0].Value)

return
}
Expand Down

0 comments on commit 82998b4

Please sign in to comment.