Source file src/cmd/internal/cov/mreader.go

     1  // Copyright 2022 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 cov
     6  
     7  import (
     8  	"cmd/internal/bio"
     9  	"io"
    10  	"os"
    11  )
    12  
    13  // This file contains the helper "MReader", a wrapper around bio plus
    14  // an "mmap'd read-only" view of the file obtained from bio.SliceRO().
    15  // MReader is designed to implement the io.ReaderSeeker interface.
    16  // Since bio.SliceOS() is not guaranteed to succeed, MReader falls back
    17  // on explicit reads + seeks provided by bio.Reader if needed.
    18  
    19  type MReader struct {
    20  	f        *os.File
    21  	rdr      *bio.Reader
    22  	fileView []byte
    23  	off      int64
    24  }
    25  
    26  func NewMreader(f *os.File) (*MReader, error) {
    27  	rdr := bio.NewReader(f)
    28  	fi, err := f.Stat()
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  	r := MReader{
    33  		f:        f,
    34  		rdr:      rdr,
    35  		fileView: rdr.SliceRO(uint64(fi.Size())),
    36  	}
    37  	return &r, nil
    38  }
    39  
    40  func (r *MReader) Read(p []byte) (int, error) {
    41  	if r.fileView != nil {
    42  		amt := len(p)
    43  		toread := r.fileView[r.off:]
    44  		if len(toread) < 1 {
    45  			return 0, io.EOF
    46  		}
    47  		if len(toread) < amt {
    48  			amt = len(toread)
    49  		}
    50  		copy(p, toread)
    51  		r.off += int64(amt)
    52  		return amt, nil
    53  	}
    54  	return io.ReadFull(r.rdr, p)
    55  }
    56  
    57  func (r *MReader) ReadByte() (byte, error) {
    58  	if r.fileView != nil {
    59  		toread := r.fileView[r.off:]
    60  		if len(toread) < 1 {
    61  			return 0, io.EOF
    62  		}
    63  		rv := toread[0]
    64  		r.off++
    65  		return rv, nil
    66  	}
    67  	return r.rdr.ReadByte()
    68  }
    69  
    70  func (r *MReader) Seek(offset int64, whence int) (int64, error) {
    71  	if r.fileView == nil {
    72  		return r.rdr.MustSeek(offset, whence), nil
    73  	}
    74  	switch whence {
    75  	case io.SeekStart:
    76  		r.off = offset
    77  		return offset, nil
    78  	case io.SeekCurrent:
    79  		return r.off, nil
    80  	case io.SeekEnd:
    81  		r.off = int64(len(r.fileView)) + offset
    82  		return r.off, nil
    83  	}
    84  	panic("other modes not implemented")
    85  }
    86  

View as plain text