github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/maps/skipmap/skipmap_test.go (about)

     1  package skipmap
     2  
     3  import (
     4  	"math/rand"
     5  	"reflect"
     6  	"runtime"
     7  	"sync"
     8  	"sync/atomic"
     9  	"testing"
    10  
    11  	"github.com/songzhibin97/go-baseutils/base/bcomparator"
    12  	"github.com/songzhibin97/go-baseutils/sys/fastrand"
    13  )
    14  
    15  func TestSkipMap(t *testing.T) {
    16  	m := New[int64, any](bcomparator.Int64Comparator())
    17  
    18  	// Correctness.
    19  	m.Store(123, "123")
    20  	v, ok := m.Load(123)
    21  	if !ok || v != "123" || m.Len() != 1 {
    22  		t.Fatal("invalid")
    23  	}
    24  
    25  	m.Store(123, "456")
    26  	v, ok = m.Load(123)
    27  	if !ok || v != "456" || m.Len() != 1 {
    28  		t.Fatal("invalid")
    29  	}
    30  
    31  	m.Store(123, 456)
    32  	v, ok = m.Load(123)
    33  	if !ok || v != 456 || m.Len() != 1 {
    34  		t.Fatal("invalid")
    35  	}
    36  
    37  	m.Delete(123)
    38  	v, ok = m.Load(123)
    39  	if ok || m.Len() != 0 || v != nil {
    40  		t.Fatal("invalid")
    41  	}
    42  
    43  	v, loaded := m.LoadOrStore(123, 456)
    44  	if loaded || v != 456 || m.Len() != 1 {
    45  		t.Fatal("invalid")
    46  	}
    47  
    48  	v, loaded = m.LoadOrStore(123, 789)
    49  	if !loaded || v != 456 || m.Len() != 1 {
    50  		t.Fatal("invalid")
    51  	}
    52  
    53  	v, ok = m.Load(123)
    54  	if !ok || v != 456 || m.Len() != 1 {
    55  		t.Fatal("invalid")
    56  	}
    57  
    58  	v, ok = m.LoadAndDelete(123)
    59  	if !ok || v != 456 || m.Len() != 0 {
    60  		t.Fatal("invalid")
    61  	}
    62  
    63  	_, ok = m.LoadOrStore(123, 456)
    64  	if ok || m.Len() != 1 {
    65  		t.Fatal("invalid")
    66  	}
    67  
    68  	m.LoadOrStore(456, 123)
    69  	if ok || m.Len() != 2 {
    70  		t.Fatal("invalid")
    71  	}
    72  
    73  	m.Range(func(key int64, _ interface{}) bool {
    74  		if key == 123 {
    75  			m.Store(123, 123)
    76  		} else if key == 456 {
    77  			m.LoadAndDelete(456)
    78  		}
    79  		return true
    80  	})
    81  
    82  	v, ok = m.Load(123)
    83  	if !ok || v != 123 || m.Len() != 1 {
    84  		t.Fatal("invalid")
    85  	}
    86  
    87  	// Concurrent.
    88  	var wg sync.WaitGroup
    89  	for i := 0; i < 1000; i++ {
    90  		i := int64(i)
    91  		wg.Add(1)
    92  		go func() {
    93  			m.Store(i, int(i+1000))
    94  			wg.Done()
    95  		}()
    96  	}
    97  	wg.Wait()
    98  	wg.Add(1)
    99  	go func() {
   100  		m.Delete(600)
   101  		wg.Done()
   102  	}()
   103  	wg.Wait()
   104  	wg.Add(1)
   105  	var count int64
   106  	go func() {
   107  		m.Range(func(_ int64, _ interface{}) bool {
   108  			atomic.AddInt64(&count, 1)
   109  			return true
   110  		})
   111  		wg.Done()
   112  	}()
   113  	wg.Wait()
   114  
   115  	val, ok := m.Load(500)
   116  	if !ok || reflect.TypeOf(val).Kind().String() != "int" || val.(int) != 1500 {
   117  		t.Fatal("fail")
   118  	}
   119  
   120  	_, ok = m.Load(600)
   121  	if ok {
   122  		t.Fatal("fail")
   123  	}
   124  
   125  	if m.Len() != 999 || int(count) != m.Len() {
   126  		t.Fatal("fail")
   127  	}
   128  	// Correctness 2.
   129  	var m1 sync.Map
   130  	m2 := New[uint32, any](bcomparator.Uint32Comparator())
   131  	var v1, v2 interface{}
   132  	var ok1, ok2 bool
   133  	for i := 0; i < 100000; i++ {
   134  		rd := fastrand.Uint32n(10)
   135  		r1, r2 := fastrand.Uint32n(100), fastrand.Uint32n(100)
   136  		if rd == 0 {
   137  			m1.Store(r1, r2)
   138  			m2.Store(r1, r2)
   139  		} else if rd == 1 {
   140  			v1, ok1 = m1.LoadAndDelete(r1)
   141  			v2, ok2 = m2.LoadAndDelete(r1)
   142  			if ok1 != ok2 || v1 != v2 {
   143  				t.Fatal(rd, v1, ok1, v2, ok2)
   144  			}
   145  		} else if rd == 2 {
   146  			v1, ok1 = m1.LoadOrStore(r1, r2)
   147  			v2, ok2 = m2.LoadOrStore(r1, r2)
   148  			if ok1 != ok2 || v1 != v2 {
   149  				t.Fatal(rd, v1, ok1, v2, ok2, "input -> ", r1, r2)
   150  			}
   151  		} else if rd == 3 {
   152  			m1.Delete(r1)
   153  			m2.Delete(r1)
   154  		} else if rd == 4 {
   155  			m2.Range(func(key uint32, value interface{}) bool {
   156  				v, ok := m1.Load(key)
   157  				if !ok || v != value {
   158  					t.Fatal(v, ok, key, value)
   159  				}
   160  				return true
   161  			})
   162  		} else {
   163  			v1, ok1 = m1.Load(r1)
   164  			v2, ok2 = m2.Load(r1)
   165  			if ok1 != ok2 || v1 != v2 {
   166  				t.Fatal(rd, v1, ok1, v2, ok2)
   167  			}
   168  		}
   169  	}
   170  	// Correntness 3. (LoadOrStore)
   171  	// Only one LoadorStore can successfully insert its key and value.
   172  	// And the returned value is unique.
   173  	mp := New[int, any](bcomparator.IntComparator())
   174  	tmpmap := New[int64, any](bcomparator.Int64Comparator())
   175  	samekey := 123
   176  	var added int64
   177  	for i := 1; i < 1000; i++ {
   178  		wg.Add(1)
   179  		go func() {
   180  			v := fastrand.Int63()
   181  			actual, loaded := mp.LoadOrStore(samekey, v)
   182  			if !loaded {
   183  				atomic.AddInt64(&added, 1)
   184  			}
   185  			tmpmap.Store(actual.(int64), nil)
   186  			wg.Done()
   187  		}()
   188  	}
   189  	wg.Wait()
   190  	if added != 1 {
   191  		t.Fatal("only one LoadOrStore can successfully insert a key and value")
   192  	}
   193  	if tmpmap.Len() != 1 {
   194  		t.Fatal("only one value can be returned from LoadOrStore")
   195  	}
   196  	// Correntness 4. (LoadAndDelete)
   197  	// Only one LoadAndDelete can successfully get a value.
   198  	mp = New[int, any](bcomparator.IntComparator())
   199  	tmpmap = New[int64, any](bcomparator.Int64Comparator())
   200  	samekey = 123
   201  	added = 0 // int64
   202  	mp.Store(samekey, 555)
   203  	for i := 1; i < 1000; i++ {
   204  		wg.Add(1)
   205  		go func() {
   206  			value, loaded := mp.LoadAndDelete(samekey)
   207  			if loaded {
   208  				atomic.AddInt64(&added, 1)
   209  				if value != 555 {
   210  					panic("invalid")
   211  				}
   212  			}
   213  			wg.Done()
   214  		}()
   215  	}
   216  	wg.Wait()
   217  	if added != 1 {
   218  		t.Fatal("Only one LoadAndDelete can successfully get a value")
   219  	}
   220  
   221  	// Correntness 5. (LoadOrStoreLazy)
   222  	mp = New[int, any](bcomparator.IntComparator())
   223  	tmpmap = New[int64, any](bcomparator.Int64Comparator())
   224  	samekey = 123
   225  	added = 0
   226  	var fcalled int64
   227  	valuef := func() interface{} {
   228  		atomic.AddInt64(&fcalled, 1)
   229  		return fastrand.Int63()
   230  	}
   231  	for i := 1; i < 1000; i++ {
   232  		wg.Add(1)
   233  		go func() {
   234  			actual, loaded := mp.LoadOrStoreLazy(samekey, valuef)
   235  			if !loaded {
   236  				atomic.AddInt64(&added, 1)
   237  			}
   238  			tmpmap.Store(actual.(int64), nil)
   239  			wg.Done()
   240  		}()
   241  	}
   242  	wg.Wait()
   243  	if added != 1 || fcalled != 1 {
   244  		t.Fatal("only one LoadOrStoreLazy can successfully insert a key and value")
   245  	}
   246  	if tmpmap.Len() != 1 {
   247  		t.Fatal("only one value can be returned from LoadOrStoreLazy")
   248  	}
   249  }
   250  
   251  func TestSkipMapDesc(t *testing.T) {
   252  	m := New[int, any](bcomparator.ReverseComparator(bcomparator.IntComparator()))
   253  	cases := []int{10, 11, 12}
   254  	for _, v := range cases {
   255  		m.Store(v, nil)
   256  	}
   257  	i := len(cases) - 1
   258  	m.Range(func(key int, _ interface{}) bool {
   259  		if key != cases[i] {
   260  			t.Fail()
   261  		}
   262  		i--
   263  		return true
   264  	})
   265  }
   266  
   267  /* Test from sync.Map */
   268  func TestConcurrentRange(t *testing.T) {
   269  	const mapSize = 1 << 10
   270  
   271  	m := New[int64, any](bcomparator.Int64Comparator())
   272  	for n := int64(1); n <= mapSize; n++ {
   273  		m.Store(n, int64(n))
   274  	}
   275  
   276  	done := make(chan struct{})
   277  	var wg sync.WaitGroup
   278  	defer func() {
   279  		close(done)
   280  		wg.Wait()
   281  	}()
   282  	for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
   283  		r := rand.New(rand.NewSource(g))
   284  		wg.Add(1)
   285  		go func(g int64) {
   286  			defer wg.Done()
   287  			for i := int64(0); ; i++ {
   288  				select {
   289  				case <-done:
   290  					return
   291  				default:
   292  				}
   293  				for n := int64(1); n < mapSize; n++ {
   294  					if r.Int63n(mapSize) == 0 {
   295  						m.Store(n, n*i*g)
   296  					} else {
   297  						m.Load(n)
   298  					}
   299  				}
   300  			}
   301  		}(g)
   302  	}
   303  
   304  	iters := 1 << 10
   305  	if testing.Short() {
   306  		iters = 16
   307  	}
   308  	for n := iters; n > 0; n-- {
   309  		seen := make(map[int64]bool, mapSize)
   310  
   311  		m.Range(func(ki int64, vi interface{}) bool {
   312  			k, v := ki, vi.(int64)
   313  			if v%k != 0 {
   314  				t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   315  			}
   316  			if seen[k] {
   317  				t.Fatalf("Range visited key %v twice", k)
   318  			}
   319  			seen[k] = true
   320  			return true
   321  		})
   322  
   323  		if len(seen) != mapSize {
   324  			t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   325  		}
   326  	}
   327  }