Skip to content

Commit 7378173

Browse files
committed
Implementing uint64 SeqNums
1 parent c7d7aee commit 7378173

20 files changed

+268
-108
lines changed

field_map.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,21 @@ func (m FieldMap) GetInt(tag Tag) (int, MessageRejectError) {
176176
return int(val), err
177177
}
178178

179+
// GetInt is a GetField wrapper for int fields.
180+
func (m FieldMap) GetUint64(tag Tag) (uint64, MessageRejectError) {
181+
bytes, err := m.GetBytes(tag)
182+
if err != nil {
183+
return 0, err
184+
}
185+
186+
var val FIXUint64
187+
if val.Read(bytes) != nil {
188+
err = IncorrectDataFormatForValue(tag)
189+
}
190+
191+
return uint64(val), err
192+
}
193+
179194
// GetInt is a lock free GetField wrapper for int fields.
180195
func (m FieldMap) getIntNoLock(tag Tag) (int, MessageRejectError) {
181196
bytes, err := m.getBytesNoLock(tag)
@@ -270,6 +285,12 @@ func (m *FieldMap) SetInt(tag Tag, value int) *FieldMap {
270285
return m.SetBytes(tag, v.Write())
271286
}
272287

288+
// SetUint64 is a SetField wrapper for int fields.
289+
func (m *FieldMap) SetUint64(tag Tag, value uint64) *FieldMap {
290+
v := FIXUint64(value)
291+
return m.SetBytes(tag, v.Write())
292+
}
293+
273294
// SetString is a SetField wrapper for string fields.
274295
func (m *FieldMap) SetString(tag Tag, value string) *FieldMap {
275296
return m.SetBytes(tag, []byte(value))

fix_uint.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) quickfixengine.org All rights reserved.
2+
//
3+
// This file may be distributed under the terms of the quickfixengine.org
4+
// license as defined by quickfixengine.org and appearing in the file
5+
// LICENSE included in the packaging of this file.
6+
//
7+
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
8+
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
9+
// PARTICULAR PURPOSE.
10+
//
11+
// See http://www.quickfixengine.org/LICENSE for licensing information.
12+
//
13+
// Contact ask@quickfixengine.org if any conditions of this licensing
14+
// are not clear to you.
15+
16+
package quickfix
17+
18+
import (
19+
"errors"
20+
"strconv"
21+
)
22+
23+
// atoi is similar to the function in strconv, but is tuned for ints appearing in FIX field types.
24+
func atou(d []byte) (uint64, error) {
25+
// if d[0] == asciiMinus {
26+
// n, err := parseUInt64(d[1:])
27+
// return (-1) * n, err
28+
// }
29+
30+
return parseUInt64(d)
31+
}
32+
33+
// parseUInt is similar to the function in strconv, but is tuned for ints appearing in FIX field types.
34+
func parseUInt64(d []byte) (n uint64, err error) {
35+
if len(d) == 0 {
36+
err = errors.New("empty bytes")
37+
return
38+
}
39+
40+
for _, dec := range d {
41+
if dec < ascii0 || dec > ascii9 {
42+
err = errors.New("invalid format")
43+
return
44+
}
45+
46+
n = n*10 + (uint64(dec) - ascii0)
47+
}
48+
49+
return
50+
}
51+
52+
// FIXInt is a FIX Int Value, implements FieldValue.
53+
type FIXUint64 uint64
54+
55+
// Int converts the FIXInt value to int.
56+
func (f FIXUint64) Uint64() uint64 { return uint64(f) }
57+
58+
func (f *FIXUint64) Read(bytes []byte) error {
59+
i, err := atou(bytes)
60+
if err != nil {
61+
return err
62+
}
63+
*f = FIXUint64(i)
64+
return nil
65+
}
66+
67+
func (f FIXUint64) Write() []byte {
68+
return strconv.AppendInt(nil, int64(f), 10)
69+
}

fix_uint_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) quickfixengine.org All rights reserved.
2+
//
3+
// This file may be distributed under the terms of the quickfixengine.org
4+
// license as defined by quickfixengine.org and appearing in the file
5+
// LICENSE included in the packaging of this file.
6+
//
7+
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
8+
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
9+
// PARTICULAR PURPOSE.
10+
//
11+
// See http://www.quickfixengine.org/LICENSE for licensing information.
12+
//
13+
// Contact ask@quickfixengine.org if any conditions of this licensing
14+
// are not clear to you.
15+
16+
package quickfix
17+
18+
import (
19+
"testing"
20+
21+
"github.com/stretchr/testify/assert"
22+
)
23+
24+
func TestFIXUInt_Write(t *testing.T) {
25+
field := FIXUint64(5)
26+
27+
assert.Equal(t, "5", string(field.Write()))
28+
}
29+
30+
func TestFIXUInt_Read(t *testing.T) {
31+
var field FIXUint64
32+
err := field.Read([]byte("15"))
33+
assert.Nil(t, err, "Unexpected error")
34+
assert.Equal(t, uint64(15), uint64(field))
35+
36+
err = field.Read([]byte("blah"))
37+
assert.NotNil(t, err, "Unexpected error")
38+
}
39+
40+
func TestFIXUInt_UInt(t *testing.T) {
41+
f := FIXUint64(4)
42+
assert.Equal(t, uint64(4), f.Uint64())
43+
}
44+
45+
func BenchmarkFIXUInt_Read(b *testing.B) {
46+
intBytes := []byte("1500")
47+
var field FIXUint64
48+
49+
for i := 0; i < b.N; i++ {
50+
_ = field.Read(intBytes)
51+
}
52+
}

in_session.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (state inSession) resendMessages(session *session, beginSeqNo, endSeqNo uin
240240
return err // We cant continue with a message that cant be parsed correctly.
241241
}
242242
msgType, _ := msg.Header.GetBytes(tagMsgType)
243-
sentMessageSeqNum, _ := msg.Header.GetInt(tagMsgSeqNum)
243+
sentMessageSeqNum, _ := msg.Header.GetUint64(tagMsgSeqNum)
244244

245245
if isAdminMessageType(msgType) {
246246
nextSeqNum = sentMessageSeqNum + 1
@@ -297,7 +297,7 @@ func (state inSession) processReject(session *session, msg *Message, rej Message
297297
}
298298

299299
if nextState.messageStash == nil {
300-
nextState.messageStash = make(map[int]*Message)
300+
nextState.messageStash = make(map[uint64]*Message)
301301
}
302302

303303
nextState.messageStash[TypedError.ReceivedTarget] = msg
@@ -387,7 +387,7 @@ func (state inSession) doTargetTooLow(session *session, msg *Message, rej target
387387
return state
388388
}
389389

390-
func (state *inSession) generateSequenceReset(session *session, beginSeqNo uint64, endSeqNo int, inReplyTo Message) (err error) {
390+
func (state *inSession) generateSequenceReset(session *session, beginSeqNo uint64, endSeqNo uint64, inReplyTo Message) (err error) {
391391
sequenceReset := NewMessage()
392392
session.fillDefaultHeader(sequenceReset, &inReplyTo)
393393

in_session_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ func (s *InSessionTestSuite) TestFIXMsgInTargetTooHigh() {
198198
}
199199
func (s *InSessionTestSuite) TestFIXMsgInTargetTooHighResendRequestChunkSize() {
200200
var tests = []struct {
201-
chunkSize int
202-
expectedEndSeqNo int
201+
chunkSize uint64
202+
expectedEndSeqNo uint64
203203
}{
204204
{0, 0},
205205
{10, 0},

internal/session_settings.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type SessionSettings struct {
1212
HeartBtIntOverride bool
1313
SessionTime *TimeRange
1414
InitiateLogon bool
15-
ResendRequestChunkSize int
15+
ResendRequestChunkSize uint64
1616
EnableLastMsgSeqNumProcessed bool
1717
EnableNextExpectedMsgSeqNum bool
1818
SkipCheckLatency bool

internal/testsuite/store_suite.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,23 @@ func (s *StoreTestSuite) TestMessageStoreSetNextMsgSeqNumRefreshIncrNextMsgSeqNu
3939
s.Require().Nil(s.MsgStore.Refresh())
4040

4141
// Then the sender and target seqnums should still be
42-
s.Equal(867, s.MsgStore.NextSenderMsgSeqNum())
43-
s.Equal(5309, s.MsgStore.NextTargetMsgSeqNum())
42+
s.Equal(uint64(867), s.MsgStore.NextSenderMsgSeqNum())
43+
s.Equal(uint64(5309), s.MsgStore.NextTargetMsgSeqNum())
4444

4545
// When the sender and target seqnums are incremented
4646
s.Require().Nil(s.MsgStore.IncrNextSenderMsgSeqNum())
4747
s.Require().Nil(s.MsgStore.IncrNextTargetMsgSeqNum())
4848

4949
// Then the sender and target seqnums should be
50-
s.Equal(868, s.MsgStore.NextSenderMsgSeqNum())
51-
s.Equal(5310, s.MsgStore.NextTargetMsgSeqNum())
50+
s.Equal(uint64(868), s.MsgStore.NextSenderMsgSeqNum())
51+
s.Equal(uint64(5310), s.MsgStore.NextTargetMsgSeqNum())
5252

5353
// When the store is refreshed from its backing store
5454
s.Require().Nil(s.MsgStore.Refresh())
5555

5656
// Then the sender and target seqnums should still be
57-
s.Equal(868, s.MsgStore.NextSenderMsgSeqNum())
58-
s.Equal(5310, s.MsgStore.NextTargetMsgSeqNum())
57+
s.Equal(uint64(868), s.MsgStore.NextSenderMsgSeqNum())
58+
s.Equal(uint64(5310), s.MsgStore.NextTargetMsgSeqNum())
5959
}
6060

6161
func (s *StoreTestSuite) TestMessageStoreReset() {
@@ -67,18 +67,18 @@ func (s *StoreTestSuite) TestMessageStoreReset() {
6767
s.Require().Nil(s.MsgStore.Reset())
6868

6969
// Then the sender and target seqnums should be
70-
s.Equal(1, s.MsgStore.NextSenderMsgSeqNum())
71-
s.Equal(1, s.MsgStore.NextTargetMsgSeqNum())
70+
s.Equal(uint64(1), s.MsgStore.NextSenderMsgSeqNum())
71+
s.Equal(uint64(1), s.MsgStore.NextTargetMsgSeqNum())
7272

7373
// When the store is refreshed from its backing store
7474
s.Require().Nil(s.MsgStore.Refresh())
7575

7676
// Then the sender and target seqnums should still be
77-
s.Equal(1, s.MsgStore.NextSenderMsgSeqNum())
78-
s.Equal(1, s.MsgStore.NextTargetMsgSeqNum())
77+
s.Equal(uint64(1), s.MsgStore.NextSenderMsgSeqNum())
78+
s.Equal(uint64(1), s.MsgStore.NextTargetMsgSeqNum())
7979
}
8080

81-
func (s *StoreTestSuite) fetchMessages(beginSeqNum, endSeqNum int) (msgs [][]byte) {
81+
func (s *StoreTestSuite) fetchMessages(beginSeqNum, endSeqNum uint64) (msgs [][]byte) {
8282
s.T().Helper()
8383

8484
// Fetch messages from the new iterator
@@ -102,16 +102,16 @@ func (s *StoreTestSuite) fetchMessages(beginSeqNum, endSeqNum int) (msgs [][]byt
102102

103103
func (s *StoreTestSuite) TestMessageStoreSaveMessageGetMessage() {
104104
// Given the following saved messages
105-
expectedMsgsBySeqNum := map[int]string{
105+
expectedMsgsBySeqNum := map[uint64]string{
106106
1: "In the frozen land of Nador",
107107
2: "they were forced to eat Robin's minstrels",
108108
3: "and there was much rejoicing",
109109
}
110-
var seqNums []int
110+
var seqNums []uint64
111111
for seqNum := range expectedMsgsBySeqNum {
112112
seqNums = append(seqNums, seqNum)
113113
}
114-
sort.Ints(seqNums)
114+
sort.Slice(seqNums, func(i, j int) bool { return seqNums[i] < seqNums[j] })
115115
for _, seqNum := range seqNums {
116116
s.Require().Nil(s.MsgStore.SaveMessage(seqNum, []byte(expectedMsgsBySeqNum[seqNum])))
117117
}
@@ -142,20 +142,20 @@ func (s *StoreTestSuite) TestMessageStoreSaveMessageAndIncrementGetMessage() {
142142
s.Require().Nil(s.MsgStore.SetNextSenderMsgSeqNum(420))
143143

144144
// Given the following saved messages
145-
expectedMsgsBySeqNum := map[int]string{
145+
expectedMsgsBySeqNum := map[uint64]string{
146146
1: "In the frozen land of Nador",
147147
2: "they were forced to eat Robin's minstrels",
148148
3: "and there was much rejoicing",
149149
}
150-
var seqNums []int
150+
var seqNums []uint64
151151
for seqNum := range expectedMsgsBySeqNum {
152152
seqNums = append(seqNums, seqNum)
153153
}
154-
sort.Ints(seqNums)
154+
sort.Slice(seqNums, func(i, j int) bool { return seqNums[i] < seqNums[j] })
155155
for _, seqNum := range seqNums {
156156
s.Require().Nil(s.MsgStore.SaveMessageAndIncrNextSenderMsgSeqNum(seqNum, []byte(expectedMsgsBySeqNum[seqNum])))
157157
}
158-
s.Equal(423, s.MsgStore.NextSenderMsgSeqNum())
158+
s.Equal(uint64(423), s.MsgStore.NextSenderMsgSeqNum())
159159

160160
// When the messages are retrieved from the MessageStore
161161
actualMsgs := s.fetchMessages(1, 3)
@@ -172,7 +172,7 @@ func (s *StoreTestSuite) TestMessageStoreSaveMessageAndIncrementGetMessage() {
172172
// And the messages are retrieved from the MessageStore
173173
actualMsgs = s.fetchMessages(1, 3)
174174

175-
s.Equal(423, s.MsgStore.NextSenderMsgSeqNum())
175+
s.Equal(uint64(423), s.MsgStore.NextSenderMsgSeqNum())
176176

177177
// Then the messages should still be
178178
s.Require().Len(actualMsgs, 3)
@@ -199,7 +199,7 @@ func (s *StoreTestSuite) TestMessageStoreGetMessagesVariousRanges() {
199199

200200
// When the following requests are made to the store
201201
var testCases = []struct {
202-
beginSeqNo, endSeqNo int
202+
beginSeqNo, endSeqNo uint64
203203
expectedBytes [][]byte
204204
}{
205205
{beginSeqNo: 1, endSeqNo: 1, expectedBytes: [][]byte{[]byte("hello")}},

memory_store.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ import (
2222
)
2323

2424
type memoryStore struct {
25-
senderMsgSeqNum, targetMsgSeqNum int
25+
senderMsgSeqNum, targetMsgSeqNum uint64
2626
creationTime time.Time
27-
messageMap map[int][]byte
27+
messageMap map[uint64][]byte
2828
}
2929

30-
func (store *memoryStore) NextSenderMsgSeqNum() int {
30+
func (store *memoryStore) NextSenderMsgSeqNum() uint64 {
3131
return store.senderMsgSeqNum + 1
3232
}
3333

34-
func (store *memoryStore) NextTargetMsgSeqNum() int {
34+
func (store *memoryStore) NextTargetMsgSeqNum() uint64 {
3535
return store.targetMsgSeqNum + 1
3636
}
3737

@@ -45,11 +45,11 @@ func (store *memoryStore) IncrNextTargetMsgSeqNum() error {
4545
return nil
4646
}
4747

48-
func (store *memoryStore) SetNextSenderMsgSeqNum(nextSeqNum int) error {
48+
func (store *memoryStore) SetNextSenderMsgSeqNum(nextSeqNum uint64) error {
4949
store.senderMsgSeqNum = nextSeqNum - 1
5050
return nil
5151
}
52-
func (store *memoryStore) SetNextTargetMsgSeqNum(nextSeqNum int) error {
52+
func (store *memoryStore) SetNextTargetMsgSeqNum(nextSeqNum uint64) error {
5353
store.targetMsgSeqNum = nextSeqNum - 1
5454
return nil
5555
}
@@ -80,24 +80,24 @@ func (store *memoryStore) Close() error {
8080
return nil
8181
}
8282

83-
func (store *memoryStore) SaveMessage(seqNum int, msg []byte) error {
83+
func (store *memoryStore) SaveMessage(seqNum uint64, msg []byte) error {
8484
if store.messageMap == nil {
85-
store.messageMap = make(map[int][]byte)
85+
store.messageMap = make(map[uint64][]byte)
8686
}
8787

8888
store.messageMap[seqNum] = msg
8989
return nil
9090
}
9191

92-
func (store *memoryStore) SaveMessageAndIncrNextSenderMsgSeqNum(seqNum int, msg []byte) error {
92+
func (store *memoryStore) SaveMessageAndIncrNextSenderMsgSeqNum(seqNum uint64, msg []byte) error {
9393
err := store.SaveMessage(seqNum, msg)
9494
if err != nil {
9595
return err
9696
}
9797
return store.IncrNextSenderMsgSeqNum()
9898
}
9999

100-
func (store *memoryStore) IterateMessages(beginSeqNum, endSeqNum int, cb func([]byte) error) error {
100+
func (store *memoryStore) IterateMessages(beginSeqNum, endSeqNum uint64, cb func([]byte) error) error {
101101
for seqNum := beginSeqNum; seqNum <= endSeqNum; seqNum++ {
102102
if m, ok := store.messageMap[seqNum]; ok {
103103
if err := cb(m); err != nil {
@@ -108,7 +108,7 @@ func (store *memoryStore) IterateMessages(beginSeqNum, endSeqNum int, cb func([]
108108
return nil
109109
}
110110

111-
func (store *memoryStore) GetMessages(beginSeqNum, endSeqNum int) ([][]byte, error) {
111+
func (store *memoryStore) GetMessages(beginSeqNum, endSeqNum uint64) ([][]byte, error) {
112112
var msgs [][]byte
113113
err := store.IterateMessages(beginSeqNum, endSeqNum, func(m []byte) error {
114114
msgs = append(msgs, m)

0 commit comments

Comments
 (0)