github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/stream/intervals/intervals.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:48</date>
    10  //</624342675423760384>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package intervals
    29  
    30  import (
    31  	"bytes"
    32  	"fmt"
    33  	"strconv"
    34  	"sync"
    35  )
    36  
    37  //
    38  //
    39  //
    40  //
    41  //
    42  type Intervals struct {
    43  	start  uint64
    44  	ranges [][2]uint64
    45  	mu     sync.RWMutex
    46  }
    47  
    48  //
    49  //
    50  //
    51  //
    52  //
    53  //
    54  //
    55  func NewIntervals(start uint64) *Intervals {
    56  	return &Intervals{
    57  		start: start,
    58  	}
    59  }
    60  
    61  //
    62  //
    63  func (i *Intervals) Add(start, end uint64) {
    64  	i.mu.Lock()
    65  	defer i.mu.Unlock()
    66  
    67  	i.add(start, end)
    68  }
    69  
    70  func (i *Intervals) add(start, end uint64) {
    71  	if start < i.start {
    72  		start = i.start
    73  	}
    74  	if end < i.start {
    75  		return
    76  	}
    77  	minStartJ := -1
    78  	maxEndJ := -1
    79  	j := 0
    80  	for ; j < len(i.ranges); j++ {
    81  		if minStartJ < 0 {
    82  			if (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) || (start <= i.ranges[j][1]+1 && end+1 >= i.ranges[j][1]) {
    83  				if i.ranges[j][0] < start {
    84  					start = i.ranges[j][0]
    85  				}
    86  				minStartJ = j
    87  			}
    88  		}
    89  		if (start <= i.ranges[j][1] && end+1 >= i.ranges[j][1]) || (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) {
    90  			if i.ranges[j][1] > end {
    91  				end = i.ranges[j][1]
    92  			}
    93  			maxEndJ = j
    94  		}
    95  		if end+1 <= i.ranges[j][0] {
    96  			break
    97  		}
    98  	}
    99  	if minStartJ < 0 && maxEndJ < 0 {
   100  		i.ranges = append(i.ranges[:j], append([][2]uint64{{start, end}}, i.ranges[j:]...)...)
   101  		return
   102  	}
   103  	if minStartJ >= 0 {
   104  		i.ranges[minStartJ][0] = start
   105  	}
   106  	if maxEndJ >= 0 {
   107  		i.ranges[maxEndJ][1] = end
   108  	}
   109  	if minStartJ >= 0 && maxEndJ >= 0 && minStartJ != maxEndJ {
   110  		i.ranges[maxEndJ][0] = start
   111  		i.ranges = append(i.ranges[:minStartJ], i.ranges[maxEndJ:]...)
   112  	}
   113  }
   114  
   115  //
   116  func (i *Intervals) Merge(m *Intervals) {
   117  	m.mu.RLock()
   118  	defer m.mu.RUnlock()
   119  	i.mu.Lock()
   120  	defer i.mu.Unlock()
   121  
   122  	for _, r := range m.ranges {
   123  		i.add(r[0], r[1])
   124  	}
   125  }
   126  
   127  //
   128  //
   129  //
   130  //
   131  //
   132  //
   133  //
   134  func (i *Intervals) Next() (start, end uint64) {
   135  	i.mu.RLock()
   136  	defer i.mu.RUnlock()
   137  
   138  	l := len(i.ranges)
   139  	if l == 0 {
   140  		return i.start, 0
   141  	}
   142  	if i.ranges[0][0] != i.start {
   143  		return i.start, i.ranges[0][0] - 1
   144  	}
   145  	if l == 1 {
   146  		return i.ranges[0][1] + 1, 0
   147  	}
   148  	return i.ranges[0][1] + 1, i.ranges[1][0] - 1
   149  }
   150  
   151  //
   152  func (i *Intervals) Last() (end uint64) {
   153  	i.mu.RLock()
   154  	defer i.mu.RUnlock()
   155  
   156  	l := len(i.ranges)
   157  	if l == 0 {
   158  		return 0
   159  	}
   160  	return i.ranges[l-1][1]
   161  }
   162  
   163  //
   164  //
   165  func (i *Intervals) String() string {
   166  	return fmt.Sprint(i.ranges)
   167  }
   168  
   169  //
   170  //
   171  //
   172  func (i *Intervals) MarshalBinary() (data []byte, err error) {
   173  	d := make([][]byte, len(i.ranges)+1)
   174  	d[0] = []byte(strconv.FormatUint(i.start, 36))
   175  	for j := range i.ranges {
   176  		r := i.ranges[j]
   177  		d[j+1] = []byte(strconv.FormatUint(r[0], 36) + "," + strconv.FormatUint(r[1], 36))
   178  	}
   179  	return bytes.Join(d, []byte(";")), nil
   180  }
   181  
   182  //
   183  func (i *Intervals) UnmarshalBinary(data []byte) (err error) {
   184  	d := bytes.Split(data, []byte(";"))
   185  	l := len(d)
   186  	if l == 0 {
   187  		return nil
   188  	}
   189  	if l >= 1 {
   190  		i.start, err = strconv.ParseUint(string(d[0]), 36, 64)
   191  		if err != nil {
   192  			return err
   193  		}
   194  	}
   195  	if l == 1 {
   196  		return nil
   197  	}
   198  
   199  	i.ranges = make([][2]uint64, 0, l-1)
   200  	for j := 1; j < l; j++ {
   201  		r := bytes.SplitN(d[j], []byte(","), 2)
   202  		if len(r) < 2 {
   203  			return fmt.Errorf("range %d has less then 2 elements", j)
   204  		}
   205  		start, err := strconv.ParseUint(string(r[0]), 36, 64)
   206  		if err != nil {
   207  			return fmt.Errorf("parsing the first element in range %d: %v", j, err)
   208  		}
   209  		end, err := strconv.ParseUint(string(r[1]), 36, 64)
   210  		if err != nil {
   211  			return fmt.Errorf("parsing the second element in range %d: %v", j, err)
   212  		}
   213  		i.ranges = append(i.ranges, [2]uint64{start, end})
   214  	}
   215  
   216  	return nil
   217  }
   218