map.go raw

   1  package iter
   2  
   3  import (
   4  	"sync"
   5  
   6  	"github.com/sourcegraph/conc/internal/multierror"
   7  )
   8  
   9  // Mapper is an Iterator with a result type R. It can be used to configure
  10  // the behaviour of Map and MapErr. The zero value is safe to use with
  11  // reasonable defaults.
  12  //
  13  // Mapper is also safe for reuse and concurrent use.
  14  type Mapper[T, R any] Iterator[T]
  15  
  16  // Map applies f to each element of input, returning the mapped result.
  17  //
  18  // Map always uses at most runtime.GOMAXPROCS goroutines. For a configurable
  19  // goroutine limit, use a custom Mapper.
  20  func Map[T, R any](input []T, f func(*T) R) []R {
  21  	return Mapper[T, R]{}.Map(input, f)
  22  }
  23  
  24  // Map applies f to each element of input, returning the mapped result.
  25  //
  26  // Map uses up to the configured Mapper's maximum number of goroutines.
  27  func (m Mapper[T, R]) Map(input []T, f func(*T) R) []R {
  28  	res := make([]R, len(input))
  29  	Iterator[T](m).ForEachIdx(input, func(i int, t *T) {
  30  		res[i] = f(t)
  31  	})
  32  	return res
  33  }
  34  
  35  // MapErr applies f to each element of the input, returning the mapped result
  36  // and a combined error of all returned errors.
  37  //
  38  // Map always uses at most runtime.GOMAXPROCS goroutines. For a configurable
  39  // goroutine limit, use a custom Mapper.
  40  func MapErr[T, R any](input []T, f func(*T) (R, error)) ([]R, error) {
  41  	return Mapper[T, R]{}.MapErr(input, f)
  42  }
  43  
  44  // MapErr applies f to each element of the input, returning the mapped result
  45  // and a combined error of all returned errors.
  46  //
  47  // Map uses up to the configured Mapper's maximum number of goroutines.
  48  func (m Mapper[T, R]) MapErr(input []T, f func(*T) (R, error)) ([]R, error) {
  49  	var (
  50  		res    = make([]R, len(input))
  51  		errMux sync.Mutex
  52  		errs   error
  53  	)
  54  	Iterator[T](m).ForEachIdx(input, func(i int, t *T) {
  55  		var err error
  56  		res[i], err = f(t)
  57  		if err != nil {
  58  			errMux.Lock()
  59  			// TODO: use stdlib errors once multierrors land in go 1.20
  60  			errs = multierror.Join(errs, err)
  61  			errMux.Unlock()
  62  		}
  63  	})
  64  	return res, errs
  65  }
  66