diff --git a/src/lib/bytes/Makefile b/src/lib/bytes/Makefile new file mode 100644 index 0000000000..7f10585c85 --- /dev/null +++ b/src/lib/bytes/Makefile @@ -0,0 +1,68 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +O_arm=5 +O_amd64=6 +O_386=8 +OS=568vq + +O=$(O_$(GOARCH)) +GC=$(O)g -I_obj +CC=$(O)c -FVw +AS=$(O)a +AR=6ar + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + bytes.$O\ + + +phases: a1 +_obj$D/bytes.a: phases + +a1: $(O1) + $(AR) grc _obj$D/bytes.a bytes.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/bytes.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg$D/bytes.a + +packages: _obj$D/bytes.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg$D + cp _obj$D/bytes.a $(GOROOT)/pkg$D/bytes.a diff --git a/src/lib/bytes/bytes.go b/src/lib/bytes/bytes.go new file mode 100644 index 0000000000..fe97b04958 --- /dev/null +++ b/src/lib/bytes/bytes.go @@ -0,0 +1,154 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A package of simple functions to manipulate arrays of bytes. +// Analagous to the facilities of the strings package. +package bytes + +import "utf8" + +// Compare returns an integer comparing the two byte arrays lexicographically. +// The result will be 0 if a==b, -1 if a < b, and +1 if a > b +func Compare(a, b []byte) int { + for i := 0; i < len(a) && i < len(b); i++ { + switch { + case a[i] > b[i]: + return 1 + case a[i] < b[i]: + return -1 + } + } + switch { + case len(a) < len(b): + return -1 + case len(a) > len(b): + return 1 + } + return 0 +} + +// Equal returns a boolean reporting whether a == b. +func Equal(a, b []byte) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +// Explode splits s into an array of UTF-8 sequences, one per Unicode character (still arrays of bytes). +// Invalid UTF-8 sequences become correct encodings of U+FFF8. +func Explode(s []byte) [][]byte { + a := make([][]byte, utf8.RuneCount(s)); + var size, rune int; + i := 0; + for len(s) > 0 { + rune, size = utf8.DecodeRune(s); + a[i] = s[0:size]; + s = s[size:len(s)]; + i++; + } + return a +} + +// Count counts the number of non-overlapping instances of sep in s. +func Count(s, sep []byte) int { + if len(sep) == 0 { + return utf8.RuneCount(s)+1 + } + c := sep[0]; + n := 0; + for i := 0; i+len(sep) <= len(s); i++ { + if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) { + n++; + i += len(sep)-1 + } + } + return n +} + +// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. +func Index(s, sep []byte) int { + n := len(sep); + if n == 0 { + return 0 + } + c := sep[0]; + for i := 0; i+n <= len(s); i++ { + if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) { + return i + } + } + return -1 +} + +// Split returns the array representing the subarrays of s separated by sep. Adjacent +// occurrences of sep produce empty subarrays. If sep is empty, it is the same as Explode. +func Split(s, sep []byte) [][]byte { + if len(sep) == 0 { + return Explode(s) + } + c := sep[0]; + start := 0; + n := Count(s, sep)+1; + a := make([][]byte, n); + na := 0; + for i := 0; i+len(sep) <= len(s); i++ { + if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) { + a[na] = s[start:i]; + na++; + start = i+len(sep); + i += len(sep)-1 + } + } + a[na] = s[start:len(s)]; + return a +} + +// Join concatenates the elements of a to create a single byte array. The separator +// sep is placed between elements in the resulting array. +func Join(a [][]byte, sep []byte) []byte { + if len(a) == 0 { + return []byte{} + } + if len(a) == 1 { + return a[0] + } + n := len(sep) * (len(a)-1); + for i := 0; i < len(a); i++ { + n += len(a[i]) + } + + b := make([]byte, n); + bp := 0; + for i := 0; i < len(a); i++ { + s := a[i]; + for j := 0; j < len(s); j++ { + b[bp] = s[j]; + bp++ + } + if i + 1 < len(a) { + s = sep; + for j := 0; j < len(s); j++ { + b[bp] = s[j]; + bp++ + } + } + } + return b +} + +// HasPrefix tests whether the byte array s begins with prefix. +func HasPrefix(s, prefix []byte) bool { + return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix) +} + +// HasSuffix tests whether the byte array s ends with suffix. +func HasSuffix(s, suffix []byte) bool { + return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):len(s)], suffix) +} diff --git a/src/lib/bytes/bytes_test.go b/src/lib/bytes/bytes_test.go new file mode 100644 index 0000000000..26b3fc21d0 --- /dev/null +++ b/src/lib/bytes/bytes_test.go @@ -0,0 +1,130 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bytes + +import ( + "bytes"; + "io"; + "testing"; +) + +func eq(a, b []string) bool { + if len(a) != len(b) { + return false; + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false; + } + } + return true; +} + +func arrayOfString(a [][]byte) []string { + result := make([]string, len(a)); + for j := 0; j < len(a); j++ { + result[j] = string(a[j]) + } + return result +} + +// For ease of reading, the test cases use strings that are converted to byte +// arrays before invoking the functions. + +var abcd = "abcd" +var faces = "☺☻☹" +var commas = "1,2,3,4" +var dots = "1....2....3....4" + +type CompareTest struct { + a string; + b string; + cmp int; +} +var comparetests = []CompareTest { + CompareTest{ "", "", 0 }, + CompareTest{ "a", "", 1 }, + CompareTest{ "", "a", -1 }, + CompareTest{ "abc", "abc", 0 }, + CompareTest{ "ab", "abc", -1 }, + CompareTest{ "abc", "ab", 1 }, + CompareTest{ "x", "ab", 1 }, + CompareTest{ "ab", "x", -1 }, + CompareTest{ "x", "a", 1 }, + CompareTest{ "b", "x", -1 }, +} + +func TestCompare(t *testing.T) { + for i := 0; i < len(comparetests); i++ { + tt := comparetests[i]; + a := io.StringBytes(tt.a); + b := io.StringBytes(tt.b); + cmp := Compare(a, b); + eql := Equal(a, b); + if cmp != tt.cmp { + t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp); + } + if eql != (tt.cmp==0) { + t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql); + } + } +} + + +type ExplodeTest struct { + s string; + a []string; +} +var explodetests = []ExplodeTest { + ExplodeTest{ abcd, []string{"a", "b", "c", "d"} }, + ExplodeTest{ faces, []string{"☺", "☻", "☹" } }, +} +func TestExplode(t *testing.T) { + for i := 0; i < len(explodetests); i++ { + tt := explodetests[i]; + a := Explode(io.StringBytes(tt.s)); + result := arrayOfString(a); + if !eq(result, tt.a) { + t.Errorf(`Explode("%s") = %v; want %v`, tt.s, result, tt.a); + continue; + } + s := Join(a, []byte{}); + if string(s) != tt.s { + t.Errorf(`Join(Explode("%s"), "") = "%s"`, tt.s, s); + } + } +} + + +type SplitTest struct { + s string; + sep string; + a []string; +} +var splittests = []SplitTest { + SplitTest{ abcd, "a", []string{"", "bcd"} }, + SplitTest{ abcd, "z", []string{"abcd"} }, + SplitTest{ abcd, "", []string{"a", "b", "c", "d"} }, + SplitTest{ commas, ",", []string{"1", "2", "3", "4"} }, + SplitTest{ dots, "...", []string{"1", ".2", ".3", ".4"} }, + SplitTest{ faces, "☹", []string{"☺☻", ""} }, + SplitTest{ faces, "~", []string{faces} }, + SplitTest{ faces, "", []string{"☺", "☻", "☹"} }, +} +func TestSplit(t *testing.T) { + for i := 0; i < len(splittests); i++ { + tt := splittests[i]; + a := Split(io.StringBytes(tt.s), io.StringBytes(tt.sep)); + result := arrayOfString(a); + if !eq(result, tt.a) { + t.Errorf(`Split("%s", "%s") = %v; want %v`, tt.s, tt.sep, result, tt.a); + continue; + } + s := Join(a, io.StringBytes(tt.sep)); + if string(s) != tt.s { + t.Errorf(`Join(Split("%s", "%s"), "%s") = "%s"`, tt.s, tt.sep, tt.sep, s); + } + } +}