github.com/josephvusich/fdf@v0.0.0-20230522095411-9326dd32e33f/comparer.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  )
     8  
     9  type comparer interface {
    10  	AreEqual(a, b *fileRecord) bool
    11  	HashFunc(*fileRecord) interface{}
    12  }
    13  
    14  type propertyComparer struct {
    15  	getter func(*fileRecord) string
    16  	ranges [][2]int
    17  }
    18  
    19  func (c *propertyComparer) AreEqual(a, b *fileRecord) bool {
    20  	for _, r := range c.ranges {
    21  		if getRange(c.getter(a), r[0], r[1]) != getRange(c.getter(b), r[0], r[1]) {
    22  			return false
    23  		}
    24  	}
    25  	return true
    26  }
    27  
    28  func (c *propertyComparer) HashFunc(r *fileRecord) interface{} {
    29  	return c.getter(r)
    30  }
    31  
    32  func getRange(s string, offset, length int) (partial string) {
    33  	if length == 0 {
    34  		return ""
    35  	}
    36  	defer func() {
    37  		if r := recover(); r != nil {
    38  			partial = ""
    39  		}
    40  	}()
    41  	if offset < 0 {
    42  		offset += len(s)
    43  		for offset < 0 {
    44  			offset++
    45  			if length > 0 {
    46  				length--
    47  			}
    48  		}
    49  	}
    50  	if length < 0 {
    51  		length += 1 + len(s)
    52  	} else {
    53  		length += offset
    54  	}
    55  	partial = s[offset:length]
    56  	return partial
    57  }
    58  
    59  func newComparer(input string, getter func(*fileRecord) string) (*propertyComparer, error) {
    60  	c := &propertyComparer{
    61  		getter: getter,
    62  	}
    63  
    64  	if input == ":" {
    65  		input = "0:-1"
    66  	}
    67  
    68  	for _, r := range strings.Split(input, ",") {
    69  		values := strings.Split(r, ":")
    70  		if len(values) != 2 {
    71  			return nil, fmt.Errorf("invalid range spec: %s", r)
    72  		}
    73  
    74  		var nums [2]int
    75  		for i, v := range values {
    76  			n, err := strconv.Atoi(v)
    77  			if err != nil {
    78  				return nil, fmt.Errorf("invalid range spec `%s`: %w", r, err)
    79  			}
    80  			nums[i] = n
    81  		}
    82  
    83  		c.ranges = append(c.ranges, nums)
    84  	}
    85  	return c, nil
    86  }