From f2a268b33c315ef2fad849207428bd55aedd2302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 5 Apr 2021 17:28:28 -0700 Subject: [PATCH] no need to sort, fields are already ordered --- runtime/interpreter/encode.go | 27 +--- runtime/tests/interpreter/interpreter_test.go | 152 ++++++++++++------ 2 files changed, 111 insertions(+), 68 deletions(-) diff --git a/runtime/interpreter/encode.go b/runtime/interpreter/encode.go index 82be78096e..642b24601c 100644 --- a/runtime/interpreter/encode.go +++ b/runtime/interpreter/encode.go @@ -23,7 +23,6 @@ import ( "fmt" "io" "math/big" - "sort" "strconv" "strings" @@ -808,25 +807,12 @@ func (e *Encoder) prepareCompositeValue( interface{}, error, ) { - fieldPairs := v.Fields.pairs - fieldLen := len(fieldPairs) + fields := make(cborArray, v.Fields.Len()*2) - // Sort field names lexicographically. - fieldNames := make([]string, fieldLen) - - index := 0 - for name := range fieldPairs { - fieldNames[index] = name - index++ - } - - sort.Strings(fieldNames) - - // Create fields (key and value) array, sorted by field name. - fields := make(cborArray, fieldLen*2) - - for i, fieldName := range fieldNames { - value := fieldPairs[fieldName].Value + i := 0 + for pair := v.Fields.Oldest(); pair != nil; pair = pair.Next() { + fieldName := pair.Key + value := pair.Value valuePath := append(path[:], fieldName) @@ -835,7 +821,8 @@ func (e *Encoder) prepareCompositeValue( return nil, err } - fields[i*2], fields[i*2+1] = fieldName, prepared + fields[i], fields[i+1] = fieldName, prepared + i += 2 } location, err := e.prepareLocation(v.Location) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 57e70ee5d9..e3bf2bd8a1 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -7918,11 +7918,11 @@ func TestInterpretForce(t *testing.T) { }) } -func permutations(xs []string) (res [][]string) { - var f func([]string, int) - f = func(a []string, k int) { +func permutations(xs [][]byte) (res [][][]byte) { + var f func([][]byte, int) + f = func(a [][]byte, k int) { if k == len(a) { - res = append(res, append([]string{}, a...)) + res = append(res, append([][]byte{}, a...)) } else { for i := k; i < len(xs); i++ { a[k], a[i] = a[i], a[k] @@ -7941,43 +7941,92 @@ func TestInterpretCompositeValueFieldEncodingOrder(t *testing.T) { t.Parallel() - fieldValues := map[string]int{ - "a": 1, - "b": 2, - "c": 3, + fieldValues := map[byte]byte{ + 'a': 1, + 'b': 2, + 'c': 3, } - initializations := make([]string, 0, len(fieldValues)) + // prepare initialization statements + + initializations := make([][]byte, 0, len(fieldValues)) + expectedEncodings := make([][]byte, 0, len(fieldValues)) for name, value := range fieldValues { - initialization := fmt.Sprintf("self.%s = %d", name, value) - initializations = append(initializations, initialization) + initialization := fmt.Sprintf("self.%c = %d", name, value) + initializations = append(initializations, []byte(initialization)) + + expectedEncodings = append(expectedEncodings, []byte{ + // UTF-8 string, length 1 + 0x61, + name, + // tag + 0xD8, 0x98, + // - positive bignum + 0xc2, + // - byte string, length 1 + 0x41, + value, + }) } allInitializations := permutations(initializations) + allExpectedEncodings := permutations(expectedEncodings) - encodings := make([][]byte, len(allInitializations)) + expectedPrefix := []byte{ + // tag + 0xd8, 0x84, + // array, 5 items follow + 0x85, + + // tag + 0xd8, 0xc1, + // UTF-8 string, length 4 + 0x64, + // t, e, s, t + 0x74, 0x65, 0x73, 0x74, + + // nil + 0xf6, + + // positive integer 1 + 0x1, + + // array, 6 items follow + 0x86, + } + + expectedSuffix := []byte{ + // UTF-8 string, length 4 + 0x64, + 0x54, 0x65, 0x73, 0x74, + } for i, initialization := range allInitializations { - inter := parseCheckAndInterpret(t, - fmt.Sprintf( - ` - struct Test { - let a: Int - let b: Int - let c: Int + var codeBuilder strings.Builder + codeBuilder.WriteString(` + struct Test { + let a: Int + let b: Int + let c: Int - init() { - %s - } - } + init() { + `) - let test = Test() - `, - strings.Join(initialization, "\n"), - ), - ) + for _, statement := range initialization { + codeBuilder.Write(statement) + codeBuilder.WriteRune('\n') + } + + codeBuilder.WriteString(` + } + } + + let test = Test() + `) + + inter := parseCheckAndInterpret(t, codeBuilder.String()) test := inter.Globals["test"].GetValue().(*interpreter.CompositeValue) @@ -7988,13 +8037,15 @@ func TestInterpretCompositeValueFieldEncodingOrder(t *testing.T) { encoded, _, err := interpreter.EncodeValue(test, nil, false, nil) require.NoError(t, err) - encodings[i] = encoded - } + expected := expectedPrefix[:] + + for _, expectedEncoding := range allExpectedEncodings[i] { + expected = append(expected, expectedEncoding...) + } - expected := encodings[0] + expected = append(expected, expectedSuffix...) - for _, actual := range encodings[1:] { - require.Equal(t, expected, actual) + assert.Equal(t, expected, encoded) } } @@ -8008,29 +8059,34 @@ func TestInterpretDictionaryValueEncodingOrder(t *testing.T) { "c": 3, } - initializations := make([]string, 0, len(fieldValues)) + initializations := make([][]byte, 0, len(fieldValues)) for name, value := range fieldValues { initialization := fmt.Sprintf(`xs["%s"] = %d`, name, value) - initializations = append(initializations, initialization) + initializations = append(initializations, []byte(initialization)) } for _, initialization := range permutations(initializations) { - inter := parseCheckAndInterpret(t, - fmt.Sprintf( - ` - fun construct(): {String: Int} { - let xs: {String: Int} = {} - %s - return xs - } + var codeBuilder strings.Builder + codeBuilder.WriteString(` + fun construct(): {String: Int} { + let xs: {String: Int} = {} + `) - let test = construct() - `, - strings.Join(initialization, "\n"), - ), - ) + for _, statement := range initialization { + codeBuilder.Write(statement) + codeBuilder.WriteRune('\n') + } + + codeBuilder.WriteString(` + return xs + } + + let test = construct() + `) + + inter := parseCheckAndInterpret(t, codeBuilder.String()) test := inter.Globals["test"].GetValue().(*interpreter.DictionaryValue)