window.mx raw

   1  // Copyright 2023 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package zstd
   6  
   7  // window stores up to size bytes of data.
   8  // It is implemented as a circular buffer:
   9  // sequential save calls append to the data slice until
  10  // its length reaches configured size and after that,
  11  // save calls overwrite previously saved data at off
  12  // and update off such that it always points at
  13  // the byte stored before others.
  14  type window struct {
  15  	size int
  16  	data []byte
  17  	off  int
  18  }
  19  
  20  // reset clears stored data and configures window size.
  21  func (w *window) reset(size int) {
  22  	b := w.data[:0]
  23  	if cap(b) < size {
  24  		b = []byte{:0:size}
  25  	}
  26  	w.data = b
  27  	w.off = 0
  28  	w.size = size
  29  }
  30  
  31  // len returns the number of stored bytes.
  32  func (w *window) len() uint32 {
  33  	return uint32(len(w.data))
  34  }
  35  
  36  // save stores up to size last bytes from the buf.
  37  func (w *window) save(buf []byte) {
  38  	if w.size == 0 {
  39  		return
  40  	}
  41  	if len(buf) == 0 {
  42  		return
  43  	}
  44  
  45  	if len(buf) >= w.size {
  46  		from := len(buf) - w.size
  47  		w.data = append(w.data[:0], buf[from:]...)
  48  		w.off = 0
  49  		return
  50  	}
  51  
  52  	// Update off to point to the oldest remaining byte.
  53  	free := w.size - len(w.data)
  54  	if free == 0 {
  55  		n := copy(w.data[w.off:], buf)
  56  		if n == len(buf) {
  57  			w.off += n
  58  		} else {
  59  			w.off = copy(w.data, buf[n:])
  60  		}
  61  	} else {
  62  		if free >= len(buf) {
  63  			w.data = append(w.data, buf...)
  64  		} else {
  65  			w.data = append(w.data, buf[:free]...)
  66  			w.off = copy(w.data, buf[free:])
  67  		}
  68  	}
  69  }
  70  
  71  // appendTo appends stored bytes between from and to indices to the buf.
  72  // Index from must be less or equal to index to and to must be less or equal to w.len().
  73  func (w *window) appendTo(buf []byte, from, to uint32) []byte {
  74  	dataLen := uint32(len(w.data))
  75  	from += uint32(w.off)
  76  	to += uint32(w.off)
  77  
  78  	wrap := false
  79  	if from > dataLen {
  80  		from -= dataLen
  81  		wrap = !wrap
  82  	}
  83  	if to > dataLen {
  84  		to -= dataLen
  85  		wrap = !wrap
  86  	}
  87  
  88  	if wrap {
  89  		buf = append(buf, w.data[from:]...)
  90  		return append(buf, w.data[:to]...)
  91  	} else {
  92  		return append(buf, w.data[from:to]...)
  93  	}
  94  }
  95