Repository: cloudwego/netpoll
File: nocopy_linkbuffer.go (Go)

Code before:
		}
		b.read = b.read.next
	}
	_ = pIdx
	return p, nil
}

// Peek does not have an independent lifecycle, and there is no signal to
// indicate that Peek content can be released, so Peek will not introduce mcache for now.
func (b *UnsafeLinkBuffer) Peek(n int) (p []byte, err error) {
	if n <= 0 {
		return
	}
	// check whether enough or not.
	if b.Len() < n {
		return p, fmt.Errorf("link buffer peek[%d] not enough", n)
	}
	// single node
	if b.isSingleNode(n) {
		return b.read.Peek(n), nil
	}

	// multiple nodes
	// always use malloc, since we will reuse b.cachePeek
	if b.cachePeek != nil && cap(b.cachePeek) < n {
		free(b.cachePeek)
		b.cachePeek = nil
	}
	if b.cachePeek == nil {
		b.cachePeek = malloc(n, n)
		b.cachePeek = b.cachePeek[:0] // init with zero len, will append later
	}
	p = b.cachePeek
	if len(p) >= n {
		// in case we peek smaller than last time,
		// we can return cache data directly.
		// we will reset cachePeek when Next or Skip, no worries about stale data
		return p[:n], nil
	}

	// How it works >>>>>>
	// [ -------- node0 -------- ][ --------- node1 --------- ]  <- b.read
	// [ --------------- p --------------- ]
	//                                     ^ len(p)     ^ n here
	//                           ^ scanned
	// `scanned` var is the len of last nodes which we scanned and already copied to p
	// `len(p) - scanned` is the start pos of current node for p to copy from
	// `n - len(p)` is the len of bytes we're going to append to p
	// 		we copy `len(node1)` - `len(p) - scanned` bytes in case node1 doesn't have enough data
	for scanned, node := 0, b.read; len(p) < n; node = node.next {
		l := node.Len()

Review comment (performance):
here should notice that currently malloc(4095, 4095) may return a slice (len=4095, cap=4096).  But I see seems it not effect the logic bellow. Just for a infromation when using cap of a buffer from mcache



Code after:
		}
		b.read = b.read.next
	}
	_ = pIdx
	return p, nil
}

// Peek does not have an independent lifecycle, and there is no signal to
// indicate that Peek content can be released, so Peek will not introduce mcache for now.
func (b *UnsafeLinkBuffer) Peek(n int) (p []byte, err error) {
	if n <= 0 {
		return
	}
	// check whether enough or not.
	if b.Len() < n {
		return p, fmt.Errorf("link buffer peek[%d] not enough", n)
	}
	// single node
	if b.isSingleNode(n) {
		return b.read.Peek(n), nil
	}

	// multiple nodes

	// try to make use of the cap of b.cachePeek, if can't, free it.
	if b.cachePeek != nil && cap(b.cachePeek) < n {
		free(b.cachePeek)
		b.cachePeek = nil
	}
	if b.cachePeek == nil {
		b.cachePeek = malloc(0, n) // init with zero len, will append later
	}
	p = b.cachePeek
	if len(p) >= n {
		// in case we peek smaller than last time,
		// we can return cache data directly.
		// we will reset cachePeek when Next or Skip, no worries about stale data
		return p[:n], nil
	}

	// How it works >>>>>>
	// [ -------- node0 -------- ][ --------- node1 --------- ]  <- b.read
	// [ --------------- p --------------- ]
	//                                     ^ len(p)     ^ n here
	//                           ^ scanned
	// `scanned` var is the len of last nodes which we scanned and already copied to p
	// `len(p) - scanned` is the start pos of current node for p to copy from
	// `n - len(p)` is the len of bytes we're going to append to p
	// 		we copy `len(node1)` - `len(p) - scanned` bytes in case node1 doesn't have enough data
	for scanned, node := 0, b.read; len(p) < n; node = node.next {
		l := node.Len()