github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/base/fileRange.go (about) 1 // Copyright 2021 The TrueBlocks Authors. All rights reserved. 2 // Use of this source code is governed by a license that can 3 // be found in the LICENSE file. 4 5 package base 6 7 import ( 8 "errors" 9 "fmt" 10 "path/filepath" 11 "regexp" 12 "strings" 13 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config" 15 ) 16 17 type RecordRange struct { 18 First uint64 19 Last uint64 20 } 21 22 type FileRange struct { 23 First Blknum 24 Last Blknum 25 } 26 type BlockRange FileRange // sugar 27 type TimestampRange struct { 28 First Timestamp 29 Last Timestamp 30 } 31 32 var NotARange = FileRange{First: NOPOSN, Last: NOPOSN} 33 34 // RangeFromFilename returns a FileRange and ignore any errors 35 func RangeFromFilename(path string) (blkRange FileRange) { 36 rng, _ := RangeFromFilenameE(path) 37 return rng 38 } 39 40 // RangeFromFilenameE returns a block range given a chunk filename. The format of filenames may be start-end.bin (start and end are nine digit 41 // and zero-padded to the left) or start.txt 42 func RangeFromFilenameE(path string) (blkRange FileRange, err error) { 43 _, fn := filepath.Split(path) 44 if strings.Contains(fn, ".") { 45 fn = strings.Split(fn, ".")[0] 46 } else { 47 var digitCheck = regexp.MustCompile(`^[0-9]+$`) 48 if !digitCheck.MatchString(strings.Replace(fn, "-", "", -1)) { 49 return blkRange, errors.New("not a valid range " + fn) 50 } 51 } 52 53 parts := strings.Split(fn, "-") 54 if len(parts) > 1 { 55 trimmed0 := strings.TrimLeft(parts[0], "0") 56 trimmed1 := strings.TrimLeft(parts[1], "0") 57 blkRange.First = MustParseBlknum(trimmed0) 58 blkRange.Last = MustParseBlknum(trimmed1) 59 } else { 60 trimmed0 := strings.TrimLeft(parts[0], "0") 61 blkRange.First = MustParseBlknum(trimmed0) 62 blkRange.Last = blkRange.First 63 } 64 65 return 66 } 67 68 // RangeFromRangeString returns a file range from a string 69 func RangeFromRangeString(rngStr string) FileRange { 70 return RangeFromFilename(filepath.Join(config.PathToIndex("mainnet"), "finalized", rngStr+".bin")) // okay to use mainnet since we're only interested in range 71 } 72 73 func (r FileRange) String() string { 74 return fmt.Sprintf("%09d-%09d", r.First, r.Last) 75 } 76 77 // RangeToFilename returns a fileName and existence bool given a file range and a type 78 func (r *FileRange) RangeToFilename(chain string) string { 79 return filepath.Join(config.PathToIndex(chain), "finalized", r.String()+".bin") 80 } 81 82 // Follows returns true if the range is strictly after the needle range. 83 // (If 'sequential' is true, then the first block in the range must be 84 // one more than the last block in the needle range.) 85 func (r *FileRange) Follows(needle FileRange, sequential bool) bool { 86 if sequential { 87 return r.First == needle.Last+1 88 } 89 return r.LaterThan(needle) 90 } 91 92 // Preceeds returns true if the range is strictly before the needle range. 93 // (If 'sequential' is true, then the last block in the range must be 94 // one less than the first block in the needle range.) If the needle range 95 // starts at zero, returns false (nothing is before the first range) 96 func (r *FileRange) Preceeds(needle FileRange, sequential bool) bool { 97 if sequential { 98 if needle.First == 0 { 99 return false 100 } 101 return r.Last == needle.First-1 102 } 103 return r.EarlierThan(needle) 104 } 105 106 // Intersects returns true if the two ranges intersect 107 func (r *FileRange) Intersects(needle FileRange) bool { 108 return !r.EarlierThan(needle) && !r.LaterThan(needle) 109 } 110 111 // EarlierThan returns true if range is strictly before the given needle range 112 func (r *FileRange) EarlierThan(needle FileRange) bool { 113 return r.Last < needle.First 114 } 115 116 // LaterThan returns true if range is strictly after the given needle range 117 func (r *FileRange) LaterThan(needle FileRange) bool { 118 return r.First > needle.Last 119 } 120 121 // IntersectsB returns true if the block is inside the range (inclusive on both ends) 122 func (r *FileRange) IntersectsB(bn Blknum) bool { 123 return r.Intersects(FileRange{First: bn, Last: bn}) 124 } 125 126 // EarlierThanB returns true if the range is strictly before the given block 127 func (r *FileRange) EarlierThanB(bn Blknum) bool { 128 return r.EarlierThan(FileRange{First: bn, Last: bn}) 129 } 130 131 // LaterThanB returns true if the range is strictly after the given block 132 func (r *FileRange) LaterThanB(bn Blknum) bool { 133 return r.LaterThan(FileRange{First: bn, Last: bn}) 134 } 135 136 // Equals returns true if the two ranges are equal 137 func (r *FileRange) Equals(needle FileRange) bool { 138 return r.First == needle.First && r.Last == needle.Last 139 } 140 141 func (r *FileRange) Span() Blknum { 142 return r.Last - r.First + 1 143 } 144 145 type RangeDiff struct { 146 Min Blknum 147 In Blknum 148 Mid Blknum 149 Out Blknum 150 Max Blknum 151 } 152 153 func (r *FileRange) Overlaps(test FileRange) (rd RangeDiff) { 154 rd.Min = Min(r.First, test.First) 155 rd.In = Max(r.First, test.First) 156 rd.Out = Min(r.Last, test.Last) 157 rd.Max = Max(r.Last, test.Last) 158 rd.Mid = (rd.Max-rd.Min)/2 + rd.Min 159 return 160 }