github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/pkg/sortedmap/sortedmap.go (about)

     1  // Copyright 2018 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sortedmap
     6  
     7  import (
     8  	"errors"
     9  	"sort"
    10  	"sync"
    11  )
    12  
    13  var ErrNoSuchKey = errors.New("no such key exists")
    14  
    15  // SearchInt64s implements sort.SearchInts for int64.
    16  func SearchInt64s(a []int64, x int64) int {
    17  	return sort.Search(len(a), func(i int) bool { return a[i] >= x })
    18  }
    19  
    20  // sortedSlice is a sorted slice of unique int64s.
    21  type sortedSlice []int64
    22  
    23  // Insert inserts value v int64o the appropriate location in the slice.
    24  func (s *sortedSlice) Insert(v int64) {
    25  	// Search returns the index to insert v if it exists,
    26  	// so check that it doesn't exist before adding it.
    27  	i := SearchInt64s(*s, v)
    28  	if i < len(*s) && (*s)[i] == v {
    29  		return
    30  	}
    31  
    32  	// Grow the slice by one element.
    33  	*s = append(*s, 0)
    34  	// Move the upper part of the slice out of the way and open a hole.
    35  	copy((*s)[i+1:], (*s)[i:])
    36  	// Store the new value.
    37  	(*s)[i] = v
    38  }
    39  
    40  // Delete deletes the value v from the slice.
    41  func (s *sortedSlice) Delete(v int64) {
    42  	// Search returns the index to insert v if it doesn't exist,
    43  	// so check that it exists before deleting it.
    44  	i := SearchInt64s(*s, v)
    45  	if i >= len(*s) || (*s)[i] != v {
    46  		return
    47  	}
    48  
    49  	*s = append((*s)[:i], (*s)[i+1:]...)
    50  }
    51  
    52  // Search returns the index of v in the slice, if exists is true.
    53  // Otherwise, it is the location v would be inserted.  All indices less
    54  // than i contain values less than v.
    55  func (s *sortedSlice) Search(v int64) (i int, exists bool) {
    56  	i = SearchInt64s(*s, v)
    57  	// Does v exist, or is this just the location to insert it.
    58  	if i < len(*s) && (*s)[i] == v {
    59  		exists = true
    60  	}
    61  
    62  	return
    63  }
    64  
    65  // Map is a sorted map[int64]int64.
    66  type Map struct {
    67  	// m is the underlying map store
    68  	m map[int64]int64
    69  
    70  	// k is the sorted list of keys
    71  	k sortedSlice
    72  
    73  	// mu locks the Map.
    74  	mu sync.RWMutex
    75  }
    76  
    77  // Insert inserts a key, value pair.
    78  func (m *Map) Insert(k, v int64) {
    79  	m.mu.Lock()
    80  	defer m.mu.Unlock()
    81  
    82  	// Delete any duplicate entry.
    83  	m.deleteImpl(k)
    84  
    85  	m.m[k] = v
    86  	m.k.Insert(k)
    87  }
    88  
    89  // Delete key from map, must be called with mu held.
    90  func (m *Map) deleteImpl(k int64) {
    91  	delete(m.m, k)
    92  	m.k.Delete(k)
    93  }
    94  
    95  // Delete deletes the value stored at k from the map.
    96  func (m *Map) Delete(k int64) {
    97  	m.mu.Lock()
    98  	defer m.mu.Unlock()
    99  
   100  	m.deleteImpl(k)
   101  }
   102  
   103  // Get gets the value at a specific key.
   104  func (m *Map) Get(k int64) (v int64, ok bool) {
   105  	m.mu.RLock()
   106  	defer m.mu.RUnlock()
   107  
   108  	v, ok = m.m[k]
   109  	return
   110  }
   111  
   112  // NearestLessEqual returns the nearest key, value pair that exists in
   113  // the map with a key <= want.
   114  func (m *Map) NearestLessEqual(want int64) (key, value int64, err error) {
   115  	m.mu.RLock()
   116  	defer m.mu.RUnlock()
   117  
   118  	i, exists := m.k.Search(want)
   119  	// Key already exists in the map.
   120  	if exists {
   121  		return want, m.m[want], nil
   122  	}
   123  
   124  	// i - 1 contains the nearest key less than the desired key.
   125  	if i < 1 {
   126  		return 0, 0, ErrNoSuchKey
   127  	}
   128  
   129  	key = m.k[i-1]
   130  	value = m.m[key]
   131  
   132  	return key, value, nil
   133  }
   134  
   135  // NearestGreater returns the nearest key, value pair that exists in
   136  // the map with a key > want.
   137  func (m *Map) NearestGreater(want int64) (key, value int64, err error) {
   138  	m.mu.RLock()
   139  	defer m.mu.RUnlock()
   140  
   141  	// By searching for want + 1, we the lowest possible index for
   142  	// want + 1, which must either not exist or contain something
   143  	// larger than want.
   144  	i, _ := m.k.Search(want + 1)
   145  
   146  	// i is off the end of the slice, there is nothing > want.
   147  	if i >= len(m.k) {
   148  		return 0, 0, ErrNoSuchKey
   149  	}
   150  
   151  	key = m.k[i]
   152  	value = m.m[key]
   153  
   154  	return key, value, nil
   155  }
   156  
   157  func NewMap() Map {
   158  	return Map{
   159  		m: make(map[int64]int64),
   160  		k: make(sortedSlice, 0),
   161  	}
   162  }