github.com/igggame/nebulas-go@v2.1.0+incompatible/common/sorted/slice.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package sorted
    20  
    21  // Cmp function, a < b -> -1, a == b -> 0, a > b -> 1
    22  type Cmp func(a interface{}, b interface{}) int
    23  
    24  // Slice is a sorted array
    25  type Slice struct {
    26  	content []interface{}
    27  	cmp     Cmp
    28  }
    29  
    30  // NewSlice return a new slice
    31  func NewSlice(cmp Cmp) *Slice {
    32  	return &Slice{
    33  		cmp: cmp,
    34  	}
    35  }
    36  
    37  // Push a new value into slice
    38  func (s *Slice) Push(val interface{}) {
    39  	if len(s.content) == 0 {
    40  		s.content = append(s.content, val)
    41  		return
    42  	}
    43  
    44  	start, end := 0, len(s.content)-1
    45  	result, mid := 0, 0
    46  	for start <= end {
    47  		mid = (start + end) / 2
    48  		result = s.cmp(s.content[mid], val)
    49  		if result > 0 {
    50  			end = mid - 1
    51  		} else if result < 0 {
    52  			start = mid + 1
    53  		} else {
    54  			break
    55  		}
    56  	}
    57  	content := []interface{}{val}
    58  	if result > 0 {
    59  		content = append(content, s.content[mid:]...)
    60  		content = append(s.content[0:mid], content...)
    61  	} else {
    62  		content = append(content, s.content[mid+1:]...)
    63  		content = append(s.content[0:mid+1], content...)
    64  
    65  	}
    66  	s.content = content
    67  }
    68  
    69  // PopLeft pop out the min value
    70  func (s *Slice) PopLeft() interface{} {
    71  	if s.Len() > 0 {
    72  		val := s.content[0]
    73  		s.content = s.content[1:]
    74  		return val
    75  	}
    76  	return nil
    77  }
    78  
    79  // PopRight pop out the max value
    80  func (s *Slice) PopRight() interface{} {
    81  	if s.Len() > 0 {
    82  		val := s.content[s.Len()-1]
    83  		s.content = s.content[:s.Len()-1]
    84  		return val
    85  	}
    86  	return nil
    87  }
    88  
    89  // Del the given value
    90  func (s *Slice) Del(val interface{}) {
    91  	for k, v := range s.content {
    92  		if v == val {
    93  			var content []interface{}
    94  			content = append(content, s.content[k+1:]...)
    95  			content = append(s.content[0:k], content...)
    96  			s.content = content
    97  			return
    98  		}
    99  	}
   100  }
   101  
   102  // Index return the value at the given value
   103  func (s *Slice) Index(index int) interface{} {
   104  	if s.Len() > index {
   105  		return s.content[index]
   106  	}
   107  	return nil
   108  }
   109  
   110  // Len return the length of slice
   111  func (s *Slice) Len() int {
   112  	return len(s.content)
   113  }
   114  
   115  // Left return the min value, not pop out
   116  func (s *Slice) Left() interface{} {
   117  	if s.Len() > 0 {
   118  		return s.content[0]
   119  	}
   120  	return nil
   121  }
   122  
   123  // Right return the max value, not pop out
   124  func (s *Slice) Right() interface{} {
   125  	if s.Len() > 0 {
   126  		return s.content[len(s.content)-1]
   127  	}
   128  	return nil
   129  }