From 46f6da097e9775f1efdf25bf58351f842d3efafb Mon Sep 17 00:00:00 2001 From: Sean DuBois Date: Wed, 6 Mar 2024 14:32:46 -0500 Subject: [PATCH] Add UnmarshalString Before ''' 2512 B/op 83 allocs/op ''' After ''' 2016 B/op 47 allocs/op ''' --- base_lexer.go | 8 ++++---- base_lexer_test.go | 6 +++--- fuzz_test.go | 8 ++++---- marshal_test.go | 2 +- unmarshal.go | 10 ++++++++-- unmarshal_test.go | 13 ++++++------- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/base_lexer.go b/base_lexer.go index 99542ab..edd532a 100644 --- a/base_lexer.go +++ b/base_lexer.go @@ -25,12 +25,12 @@ func (e syntaxError) Error() string { } type baseLexer struct { - value []byte + value string pos int } func (l baseLexer) syntaxError() error { - return syntaxError{s: string(l.value), i: l.pos - 1} + return syntaxError{s: l.value, i: l.pos - 1} } func (l *baseLexer) unreadByte() error { @@ -157,7 +157,7 @@ func (l *baseLexer) readField() (string, error) { break } } - return string(l.value[start:stop]), nil + return l.value[start:stop], nil } // Returns symbols until line end @@ -173,7 +173,7 @@ func (l *baseLexer) readLine() (string, error) { trim++ } if ch == '\n' { - return string(l.value[start : l.pos-trim]), nil + return l.value[start : l.pos-trim], nil } } } diff --git a/base_lexer_test.go b/base_lexer_test.go index e9b91bf..dcd975a 100644 --- a/base_lexer_test.go +++ b/base_lexer_test.go @@ -16,7 +16,7 @@ func TestLexer(t *testing.T) { "with linebreak": "aaa \n", "with linebreak 2": "aaa \r\n", } { - l := &baseLexer{value: []byte(value)} + l := &baseLexer{value: value} field, err := l.readField() if err != nil { t.Fatal(err) @@ -28,7 +28,7 @@ func TestLexer(t *testing.T) { }) t.Run("syntax error", func(t *testing.T) { - l := &baseLexer{value: []byte("12NaN")} + l := &baseLexer{value: "12NaN"} _, err := l.readUint64Field() if err != nil { fmt.Println("error message:", err.Error()) @@ -38,7 +38,7 @@ func TestLexer(t *testing.T) { }) t.Run("many fields", func(t *testing.T) { - l := &baseLexer{value: []byte("aaa 123\nf1 f2\nlast")} + l := &baseLexer{value: "aaa 123\nf1 f2\nlast"} t.Run("first line", func(t *testing.T) { field, err := l.readField() diff --git a/fuzz_test.go b/fuzz_test.go index e1cc5a9..a175328 100644 --- a/fuzz_test.go +++ b/fuzz_test.go @@ -6,12 +6,12 @@ package sdp import "testing" func FuzzUnmarshal(f *testing.F) { - f.Add([]byte{}) - f.Add([]byte(CanonicalUnmarshalSDP)) - f.Fuzz(func(t *testing.T, data []byte) { + f.Add("") + f.Add(CanonicalUnmarshalSDP) + f.Fuzz(func(t *testing.T, data string) { // Check that unmarshalling any byte slice does not panic. var sd SessionDescription - if err := sd.Unmarshal(data); err != nil { + if err := sd.UnmarshalString(data); err != nil { return } // Check that we can marshal anything we unmarshalled. diff --git a/marshal_test.go b/marshal_test.go index 67b2643..502ce92 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -177,7 +177,7 @@ func TestMarshalCanonical(t *testing.T) { func BenchmarkMarshal(b *testing.B) { b.ReportAllocs() var sd SessionDescription - err := sd.Unmarshal([]byte(CanonicalUnmarshalSDP)) + err := sd.UnmarshalString(CanonicalUnmarshalSDP) if err != nil { b.Fatal(err) } diff --git a/unmarshal.go b/unmarshal.go index 0963459..180e54e 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -18,7 +18,7 @@ var ( errSDPInvalidPortValue = errors.New("sdp: invalid port value") ) -// Unmarshal is the primary function that deserializes the session description +// UnmarshalString is the primary function that deserializes the session description // message and stores it inside of a structured SessionDescription object. // // The States Transition Table describes the computation flow between functions @@ -99,7 +99,7 @@ var ( // | s15 | | 14 | | | 15 | | | | 12 | | | | | | | | | // | s16 | | 14 | | | | 15 | | | 12 | | | | | | | | | // +--------+----+-------+----+-----+----+-----+---+----+----+---+---+-----+---+---+----+---+----+ -func (s *SessionDescription) Unmarshal(value []byte) error { +func (s *SessionDescription) UnmarshalString(value string) error { l := new(lexer) l.desc = s l.value = value @@ -113,6 +113,12 @@ func (s *SessionDescription) Unmarshal(value []byte) error { return nil } +// Unmarshal converts the value into a []byte and then calls UnmarshalString. +// Callers should use the more performant UnmarshalString +func (s *SessionDescription) Unmarshal(value []byte) error { + return s.UnmarshalString(string(value)) +} + func s1(l *lexer) (stateFn, error) { return l.handleType(func(key byte) stateFn { if key == 'v' { diff --git a/unmarshal_test.go b/unmarshal_test.go index 83f2bbd..16a6420 100644 --- a/unmarshal_test.go +++ b/unmarshal_test.go @@ -303,7 +303,7 @@ func TestRoundTrip(t *testing.T) { t.Run(test.Name, func(t *testing.T) { sd := &SessionDescription{} - err := sd.Unmarshal([]byte(test.SDP)) + err := sd.UnmarshalString(test.SDP) if got, want := err, error(nil); !errors.Is(got, want) { t.Fatalf("Unmarshal:\nerr=%v\nwant=%v", got, want) } @@ -327,7 +327,7 @@ func TestRoundTrip(t *testing.T) { func TestUnmarshalRepeatTimes(t *testing.T) { sd := &SessionDescription{} - if err := sd.Unmarshal([]byte(RepeatTimesSDP)); err != nil { + if err := sd.UnmarshalString(RepeatTimesSDP); err != nil { t.Errorf("error: %v", err) } @@ -339,7 +339,7 @@ func TestUnmarshalRepeatTimes(t *testing.T) { t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", RepeatTimesSDPExpected, string(actual)) } - err = sd.Unmarshal([]byte(TimingSDP + "r=\r\n")) + err = sd.UnmarshalString(TimingSDP + "r=\r\n") if got, want := err, errSDPInvalidValue; !errors.Is(got, want) { t.Fatalf("Marshal(): err=%v, want %v", got, want) } @@ -347,7 +347,7 @@ func TestUnmarshalRepeatTimes(t *testing.T) { func TestUnmarshalTimeZones(t *testing.T) { sd := &SessionDescription{} - if err := sd.Unmarshal([]byte(TimeZonesSDP)); err != nil { + if err := sd.UnmarshalString(TimeZonesSDP); err != nil { t.Errorf("error: %v", err) } @@ -363,7 +363,7 @@ func TestUnmarshalTimeZones(t *testing.T) { func TestUnmarshalNonNilAddress(t *testing.T) { in := "v=0\r\no=0 0 0 IN IP4 0\r\ns=0\r\nc=IN IP4\r\nt=0 0\r\n" var sd SessionDescription - err := sd.Unmarshal([]byte(in)) + err := sd.UnmarshalString(in) if err != nil { t.Fatalf("failed to unmarshal %q", in) } @@ -378,10 +378,9 @@ func TestUnmarshalNonNilAddress(t *testing.T) { func BenchmarkUnmarshal(b *testing.B) { b.ReportAllocs() - raw := []byte(CanonicalUnmarshalSDP) for i := 0; i < b.N; i++ { var sd SessionDescription - err := sd.Unmarshal(raw) + err := sd.UnmarshalString(CanonicalUnmarshalSDP) if err != nil { b.Fatal(err) }