github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/buffer/view.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package buffer provides the implementation of a buffer view.
    16  package buffer
    17  
    18  import (
    19  	"bytes"
    20  	"fmt"
    21  	"io"
    22  )
    23  
    24  // View is a slice of a buffer, with convenience methods.
    25  type View []byte
    26  
    27  // NewView allocates a new buffer and returns an initialized view that covers
    28  // the whole buffer.
    29  func NewView(size int) View {
    30  	return make(View, size)
    31  }
    32  
    33  // NewViewFromBytes allocates a new buffer and copies in the given bytes.
    34  func NewViewFromBytes(b []byte) View {
    35  	return append(View(nil), b...)
    36  }
    37  
    38  // TrimFront removes the first "count" bytes from the visible section of the
    39  // buffer.
    40  func (v *View) TrimFront(count int) {
    41  	*v = (*v)[count:]
    42  }
    43  
    44  // CapLength irreversibly reduces the length of the visible section of the
    45  // buffer to the value specified.
    46  func (v *View) CapLength(length int) {
    47  	// We also set the slice cap because if we don't, one would be able to
    48  	// expand the view back to include the region just excluded. We want to
    49  	// prevent that to avoid potential data leak if we have uninitialized
    50  	// data in excluded region.
    51  	*v = (*v)[:length:length]
    52  }
    53  
    54  // Reader returns a bytes.Reader for v.
    55  func (v *View) Reader() bytes.Reader {
    56  	var r bytes.Reader
    57  	r.Reset(*v)
    58  	return r
    59  }
    60  
    61  // ToVectorisedView returns a VectorisedView containing the receiver.
    62  func (v View) ToVectorisedView() VectorisedView {
    63  	if len(v) == 0 {
    64  		return VectorisedView{}
    65  	}
    66  	return NewVectorisedView(len(v), []View{v})
    67  }
    68  
    69  // IsEmpty returns whether v is of length zero.
    70  func (v View) IsEmpty() bool {
    71  	return len(v) == 0
    72  }
    73  
    74  // Size returns the length of v.
    75  func (v View) Size() int {
    76  	return len(v)
    77  }
    78  
    79  // VectorisedView is a vectorised version of View using non contiguous memory.
    80  // It supports all the convenience methods supported by View.
    81  //
    82  // +stateify savable
    83  type VectorisedView struct {
    84  	views []View
    85  	size  int
    86  }
    87  
    88  // NewVectorisedView creates a new vectorised view from an already-allocated
    89  // slice of View and sets its size.
    90  func NewVectorisedView(size int, views []View) VectorisedView {
    91  	return VectorisedView{views: views, size: size}
    92  }
    93  
    94  // TrimFront removes the first "count" bytes of the vectorised view. It panics
    95  // if count > vv.Size().
    96  func (vv *VectorisedView) TrimFront(count int) {
    97  	for count > 0 && len(vv.views) > 0 {
    98  		if count < len(vv.views[0]) {
    99  			vv.size -= count
   100  			vv.views[0].TrimFront(count)
   101  			return
   102  		}
   103  		count -= len(vv.views[0])
   104  		vv.removeFirst()
   105  	}
   106  }
   107  
   108  // Read implements io.Reader.
   109  func (vv *VectorisedView) Read(b []byte) (copied int, err error) {
   110  	count := len(b)
   111  	for count > 0 && len(vv.views) > 0 {
   112  		if count < len(vv.views[0]) {
   113  			vv.size -= count
   114  			copy(b[copied:], vv.views[0][:count])
   115  			vv.views[0].TrimFront(count)
   116  			copied += count
   117  			return copied, nil
   118  		}
   119  		count -= len(vv.views[0])
   120  		copy(b[copied:], vv.views[0])
   121  		copied += len(vv.views[0])
   122  		vv.removeFirst()
   123  	}
   124  	if copied == 0 {
   125  		return 0, io.EOF
   126  	}
   127  	return copied, nil
   128  }
   129  
   130  // ReadToVV reads up to n bytes from vv to dstVV and removes them from vv. It
   131  // returns the number of bytes copied.
   132  func (vv *VectorisedView) ReadToVV(dstVV *VectorisedView, count int) (copied int) {
   133  	for count > 0 && len(vv.views) > 0 {
   134  		if count < len(vv.views[0]) {
   135  			vv.size -= count
   136  			dstVV.AppendView(vv.views[0][:count])
   137  			vv.views[0].TrimFront(count)
   138  			copied += count
   139  			return
   140  		}
   141  		count -= len(vv.views[0])
   142  		dstVV.AppendView(vv.views[0])
   143  		copied += len(vv.views[0])
   144  		vv.removeFirst()
   145  	}
   146  	return copied
   147  }
   148  
   149  // ReadTo reads up to count bytes from vv to dst. It also removes them from vv
   150  // unless peek is true.
   151  func (vv *VectorisedView) ReadTo(dst io.Writer, peek bool) (int, error) {
   152  	var err error
   153  	done := 0
   154  	for _, v := range vv.Views() {
   155  		var n int
   156  		n, err = dst.Write(v)
   157  		done += n
   158  		if err != nil {
   159  			break
   160  		}
   161  		if n != len(v) {
   162  			panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, len(v)))
   163  		}
   164  	}
   165  	if !peek {
   166  		vv.TrimFront(done)
   167  	}
   168  	return done, err
   169  }
   170  
   171  // CapLength irreversibly reduces the length of the vectorised view.
   172  func (vv *VectorisedView) CapLength(length int) {
   173  	if length < 0 {
   174  		length = 0
   175  	}
   176  	if vv.size < length {
   177  		return
   178  	}
   179  	vv.size = length
   180  	for i := range vv.views {
   181  		v := &vv.views[i]
   182  		if len(*v) >= length {
   183  			if length == 0 {
   184  				vv.views = vv.views[:i]
   185  			} else {
   186  				v.CapLength(length)
   187  				vv.views = vv.views[:i+1]
   188  			}
   189  			return
   190  		}
   191  		length -= len(*v)
   192  	}
   193  }
   194  
   195  // Clone returns a clone of this VectorisedView.
   196  // If the buffer argument is large enough to contain all the Views of this
   197  // VectorisedView, the method will avoid allocations and use the buffer to
   198  // store the Views of the clone.
   199  func (vv VectorisedView) Clone(buffer []View) VectorisedView {
   200  	return VectorisedView{views: append(buffer[:0], vv.views...), size: vv.size}
   201  }
   202  
   203  // PullUp returns the first "count" bytes of the vectorised view. If those
   204  // bytes aren't already contiguous inside the vectorised view, PullUp will
   205  // reallocate as needed to make them contiguous. PullUp fails and returns false
   206  // when count > vv.Size().
   207  func (vv *VectorisedView) PullUp(count int) (View, bool) {
   208  	if len(vv.views) == 0 {
   209  		return nil, count == 0
   210  	}
   211  	if count <= len(vv.views[0]) {
   212  		return vv.views[0][:count], true
   213  	}
   214  	if count > vv.size {
   215  		return nil, false
   216  	}
   217  
   218  	newFirst := NewView(count)
   219  	i := 0
   220  	for offset := 0; offset < count; i++ {
   221  		copy(newFirst[offset:], vv.views[i])
   222  		if count-offset < len(vv.views[i]) {
   223  			vv.views[i].TrimFront(count - offset)
   224  			break
   225  		}
   226  		offset += len(vv.views[i])
   227  		vv.views[i] = nil
   228  	}
   229  	// We're guaranteed that i > 0, since count is too large for the first
   230  	// view.
   231  	vv.views[i-1] = newFirst
   232  	vv.views = vv.views[i-1:]
   233  	return newFirst, true
   234  }
   235  
   236  // Size returns the size in bytes of the entire content stored in the
   237  // vectorised view.
   238  func (vv *VectorisedView) Size() int {
   239  	return vv.size
   240  }
   241  
   242  // MemSize returns the estimation size of the vv in memory, including backing
   243  // buffer data.
   244  func (vv *VectorisedView) MemSize() int {
   245  	var size int
   246  	for _, v := range vv.views {
   247  		size += cap(v)
   248  	}
   249  	return size + cap(vv.views)*viewStructSize + vectorisedViewStructSize
   250  }
   251  
   252  // ToView returns a single view containing the content of the vectorised view.
   253  //
   254  // If the vectorised view contains a single view, that view will be returned
   255  // directly.
   256  func (vv *VectorisedView) ToView() View {
   257  	if len(vv.views) == 1 {
   258  		return vv.views[0]
   259  	}
   260  	return vv.ToOwnedView()
   261  }
   262  
   263  // ToOwnedView returns a single view containing the content of the vectorised
   264  // view that vv does not own.
   265  func (vv *VectorisedView) ToOwnedView() View {
   266  	u := make([]byte, 0, vv.size)
   267  	for _, v := range vv.views {
   268  		u = append(u, v...)
   269  	}
   270  	return u
   271  }
   272  
   273  // Views returns the slice containing the all views.
   274  func (vv *VectorisedView) Views() []View {
   275  	return vv.views
   276  }
   277  
   278  // Append appends the views in a vectorised view to this vectorised view.
   279  func (vv *VectorisedView) Append(vv2 VectorisedView) {
   280  	vv.views = append(vv.views, vv2.views...)
   281  	vv.size += vv2.size
   282  }
   283  
   284  // AppendView appends the given view into this vectorised view.
   285  func (vv *VectorisedView) AppendView(v View) {
   286  	if len(v) == 0 {
   287  		return
   288  	}
   289  	vv.views = append(vv.views, v)
   290  	vv.size += len(v)
   291  }
   292  
   293  // AppendViews appends views to vv.
   294  func (vv *VectorisedView) AppendViews(views []View) {
   295  	vv.views = append(vv.views, views...)
   296  	for _, v := range views {
   297  		vv.size += len(v)
   298  	}
   299  }
   300  
   301  // Readers returns a bytes.Reader for each of vv's views.
   302  func (vv *VectorisedView) Readers() []bytes.Reader {
   303  	readers := make([]bytes.Reader, 0, len(vv.views))
   304  	for _, v := range vv.views {
   305  		readers = append(readers, v.Reader())
   306  	}
   307  	return readers
   308  }
   309  
   310  // removeFirst panics when len(vv.views) < 1.
   311  func (vv *VectorisedView) removeFirst() {
   312  	vv.size -= len(vv.views[0])
   313  	vv.views[0] = nil
   314  	vv.views = vv.views[1:]
   315  }