Skip to content

Commit

Permalink
Support for creating Slices from diskbuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
johnerikhalse committed Aug 24, 2021
1 parent 28dde2d commit a9aea0b
Show file tree
Hide file tree
Showing 4 changed files with 400 additions and 58 deletions.
1 change: 1 addition & 0 deletions internal/diskbuffer/diskbuffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Buffer interface {
ReadString(delim byte) (line string, err error)
Peek(n int) (p []byte, err error)
Size() int64
Slice(offset, len int64) Slice
}

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
Expand Down
58 changes: 0 additions & 58 deletions internal/diskbuffer/diskbuffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"os"
"testing"
Expand Down Expand Up @@ -108,27 +107,6 @@ func TestSeekWithFile(t *testing.T) {
assert.Equal(t, tlen, l)
}

//func TestSeekFirst(t *testing.T) {
// tlen := int64(1057576)
// r, hash := createReaderOfSize(tlen)
// bb, err := New(r)
// assert.Nil(t, err)
//
// l, err := bb.Size()
// assert.NoError(t, err)
// assert.Equal(t, tlen, l)
//
// assert.NoError(t, err)
// assert.Equal(t, hash, hashOfReader(bb))
//
// bb.Seek(0, 0)
//
// assert.Equal(t, hash, hashOfReader(bb))
// l, err = bb.Size()
// assert.NoError(t, err)
// assert.Equal(t, tlen, l)
//}

func TestLimitDoesNotExceed(t *testing.T) {
requestSize := int64(1057576)
r, hash := createReaderOfSize(requestSize)
Expand Down Expand Up @@ -234,15 +212,11 @@ func TestReadStringMemory(t *testing.T) {
bb.WriteString("line1\n")
bb.WriteString("line2")

fmt.Printf("Diskbuffer: %s\n", bb)
line, err := bb.ReadString('\n')
fmt.Printf("Line: <%q> :: %s\n", line, bb)
assert.NoError(t, err)
assert.Equal(t, "line1\n", line)

fmt.Printf("Diskbuffer: %s\n", bb)
line, err = bb.ReadString('\n')
fmt.Printf("Line: <%q> :: %s\n", line, bb)
assert.Error(t, err)
assert.Equal(t, "line2", line)
}
Expand Down Expand Up @@ -272,35 +246,3 @@ func TestReadString(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, "line4", line)
}

//func TestWriterReaderCalled(t *testing.T) {
// size := int64(1000)
// r, hash := createReaderOfSize(size)
//
// w, err := NewWriterOnce()
// assert.NoError(t, err)
//
// _, err = io.Copy(w, r)
// assert.NoError(t, err)
// assert.NoError(t, w.Close())
//
// bb, err := w.Reader()
// assert.NoError(t, err)
//
// assert.Equal(t, hash, hashOfReader(bb))
//
// // Subsequent calls to write and get reader will fail
// _, err = w.Reader()
// assert.Error(t, err)
//
// _, err = w.Write([]byte{1})
// assert.Error(t, err)
//}

//func TestWriterNoData(t *testing.T) {
// w, err := NewWriterOnce()
// assert.NoError(t, err)
//
// _, err = w.Reader()
// assert.Error(t, err)
//}
170 changes: 170 additions & 0 deletions internal/diskbuffer/slice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* Copyright 2021 National Library of Norway.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package diskbuffer

import (
"bytes"
"io"
)

type Slice interface {
io.Reader
io.WriterTo
io.Closer
io.Seeker
ReadBytes(delim byte) (line []byte, err error)
ReadString(delim byte) (line string, err error)
Peek(n int) (p []byte, err error)
Size() int64
}

// Slice returns a read only subset of a buffer.
func (b *buffer) Slice(offset, len int64) Slice {
if len <= 0 {
len = unlimited
}
return &slice{
buf: b,
off: offset,
len: len,
}
}

type slice struct {
buf *buffer
len int64 // Lenght of slice
off int64 // Offset in buffer where this slice starts
pos int64 // Current position in slice
}

func (s *slice) ReadAtOffset(off int64, p []byte) (n int, err error) {
start := s.off + off
l := s.len - s.pos
if l <= 0 {
return 0, io.EOF
}

pp := p
if int64(len(p)) > l {
pp = p[:l]
}
n, err = s.buf.ReadAtOffset(start, pp)
return n, err
}

func (s *slice) Read(p []byte) (n int, err error) {
n, err = s.ReadAtOffset(s.pos, p)
s.pos += int64(n)
return
}

func (s *slice) WriteTo(w io.Writer) (n int64, err error) {
p := make([]byte, 32*1024)
for {
l1, e1 := s.Read(p)
l2, e2 := w.Write(p[:l1])
n += int64(l2)
if e1 != nil {
if e1 != io.EOF {
err = e1
return
}
}
if e2 != nil {
err = e2
return
}
if l2 == 0 {
break
}
}
return
}

// Close closes the underlying buffer
func (s *slice) Close() error {
return s.buf.Close()
}

func (s *slice) Seek(offset int64, whence int) (int64, error) {
switch whence {
case io.SeekStart:
s.pos = offset
case io.SeekCurrent:
s.pos += offset
case io.SeekEnd:
s.pos = s.Size() - offset
}
return s.pos, nil
}

func (s *slice) ReadBytes(delim byte) (line []byte, err error) {
if s.len-s.pos <= 0 {
return []byte{}, io.EOF
}

p := make([]byte, 100)
off := s.pos
for {
var n int
n, err = s.ReadAtOffset(off, p)
if n > 0 {
i := bytes.IndexByte(p[:n], delim)
end := i + 1
if i < 0 {
line = append(line, p[:n]...)
off += int64(n)
} else {
// found delim
line = append(line, p[:end]...)
off += int64(end)
err = nil
break
}
}
if err != nil {
break
}
}
s.pos = off
return line, err
}

func (s *slice) ReadString(delim byte) (line string, err error) {
var bytes []byte
bytes, err = s.ReadBytes(delim)
return string(bytes), err
}

func (s *slice) Peek(n int) (p []byte, err error) {
p = make([]byte, n)
n, err = s.ReadAtOffset(s.pos, p)
return p[:n], err
}

// Len returns the number of bytes of the unread portion of the slice;
func (s *slice) Len() int64 {
return s.Size() - s.pos
}

func (s *slice) Size() int64 {
if s.len == unlimited {
return s.buf.Size() - s.off
} else {
return s.len - s.off
}
}
Loading

0 comments on commit a9aea0b

Please sign in to comment.