github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/queue/priority_queue_test.go (about)

     1  package queue
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"unsafe"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  type employee struct {
    12  	name   string
    13  	age    int
    14  	salary int64
    15  }
    16  
    17  func TestPriorityQueueItemAlignmentAndSize(t *testing.T) {
    18  	item := NewPriorityQueueItem[*employee](&employee{age: 10, name: "p0"}, 1)
    19  	t.Logf("item alignment size: %d\n", unsafe.Alignof(item))
    20  	prototype := item.(*pqItem[*employee])
    21  	t.Logf("item prototype alignment size: %d\n", unsafe.Alignof(prototype))
    22  	t.Logf("item prototype value alignment size: %d\n", unsafe.Alignof(prototype.value))
    23  	t.Logf("item prototype priority alignment size: %d\n", unsafe.Alignof(prototype.priority))
    24  	t.Logf("item prototype index alignment size: %d\n", unsafe.Alignof(prototype.index))
    25  	t.Logf("item prototype size: %d\n", unsafe.Sizeof(prototype))
    26  	t.Logf("item prototype value size: %d\n", unsafe.Sizeof(prototype.value))
    27  	t.Logf("item prototype priority size: %d\n", unsafe.Sizeof(prototype.priority))
    28  	t.Logf("item prototype index size: %d\n", unsafe.Sizeof(prototype.index))
    29  }
    30  
    31  func TestPriorityQueue_MinValueAsHighPriority(t *testing.T) {
    32  	pq := NewArrayPriorityQueue[*employee](
    33  		WithArrayPriorityQueueEnableThreadSafe[*employee](),
    34  		WithArrayPriorityQueueCapacity[*employee](32),
    35  		WithArrayPriorityQueueComparator[*employee](func(i, j ReadOnlyPQItem[*employee]) CmpEnum {
    36  			res := i.Priority() - j.Priority()
    37  			if res > 0 {
    38  				return iGTj
    39  			} else if res < 0 {
    40  				return iLTj
    41  			}
    42  			return iEQj
    43  		}),
    44  	)
    45  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p0"}, 1))
    46  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 101, name: "p1"}, 101))
    47  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p2"}, 10))
    48  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p3"}, 200))
    49  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 3, name: "p4"}, 3))
    50  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 1, name: "p5"}, 1))
    51  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 5, name: "p6"}, 5))
    52  
    53  	expectedPriorities := []int64{1, 1, 3, 5, 10, 101, 200}
    54  	for i, priority := range expectedPriorities {
    55  		item := pq.Pop()
    56  		t.Logf("%v, priority: %d", item.Value(), item.Priority())
    57  		assert.Equal(t, priority, item.Priority(), "priority", i)
    58  	}
    59  }
    60  
    61  func TestPriorityQueue_MaxValueAsHighPriority(t *testing.T) {
    62  	pq := NewArrayPriorityQueue[*employee](
    63  		WithArrayPriorityQueueEnableThreadSafe[*employee](),
    64  		WithArrayPriorityQueueCapacity[*employee](32),
    65  		WithArrayPriorityQueueComparator[*employee](func(i, j ReadOnlyPQItem[*employee]) CmpEnum {
    66  			res := j.Priority() - i.Priority()
    67  			if res > 0 {
    68  				return iGTj
    69  			} else if res < 0 {
    70  				return iLTj
    71  			}
    72  			return iEQj
    73  		}),
    74  	)
    75  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p0"}, 1))
    76  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 101, name: "p1"}, 101))
    77  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p2"}, 10))
    78  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p3"}, 200))
    79  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 3, name: "p4"}, 3))
    80  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 1, name: "p5"}, 1))
    81  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 5, name: "p6"}, 5))
    82  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p7"}, 201))
    83  
    84  	expectedPriorities := []int64{201, 200, 101, 10, 5, 3, 1, 1}
    85  	for i, priority := range expectedPriorities {
    86  		item := pq.Pop()
    87  		t.Logf("%v, priority: %d", item.Value(), item.Priority())
    88  		assert.Equal(t, priority, item.Priority(), "priority", i)
    89  	}
    90  }
    91  
    92  func TestPriorityQueue_MinValueAsHighPriority_Peek(t *testing.T) {
    93  	pq := NewArrayPriorityQueue[*employee](
    94  		WithArrayPriorityQueueEnableThreadSafe[*employee](),
    95  		WithArrayPriorityQueueCapacity[*employee](32),
    96  		WithArrayPriorityQueueComparator[*employee](func(i, j ReadOnlyPQItem[*employee]) CmpEnum {
    97  			res := i.Priority() - j.Priority()
    98  			if res > 0 {
    99  				return iGTj
   100  			} else if res < 0 {
   101  				return iLTj
   102  			}
   103  			return iEQj
   104  		}),
   105  	)
   106  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p3"}, 200))
   107  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p7"}, 201))
   108  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p2"}, 10))
   109  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 3, name: "p4"}, 3))
   110  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p0"}, 1))
   111  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 101, name: "p1"}, 101))
   112  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 1, name: "p5"}, 1))
   113  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 5, name: "p6"}, 5))
   114  
   115  	expectedPriorities := []int64{1, 1, 3, 5, 10, 101, 200, 201}
   116  	for i, priority := range expectedPriorities {
   117  		peekItem := pq.Peek()
   118  		t.Logf("peek item: %v, priority: %d", peekItem.Value(), peekItem.Priority())
   119  		item := pq.Pop()
   120  		t.Logf("%v, priority: %d", item.Value(), item.Priority())
   121  		assert.Equal(t, priority, item.Priority(), "priority", i)
   122  	}
   123  }
   124  
   125  func TestPriorityQueue_MaxValueAsHighPriority_Peek(t *testing.T) {
   126  	pq := NewArrayPriorityQueue[*employee](
   127  		WithArrayPriorityQueueEnableThreadSafe[*employee](),
   128  		WithArrayPriorityQueueCapacity[*employee](32),
   129  		WithArrayPriorityQueueComparator[*employee](func(i, j ReadOnlyPQItem[*employee]) CmpEnum {
   130  			res := j.Priority() - i.Priority()
   131  			if res > 0 {
   132  				return iGTj
   133  			} else if res < 0 {
   134  				return iLTj
   135  			}
   136  			return iEQj
   137  		}),
   138  	)
   139  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p0"}, 1))
   140  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 101, name: "p1"}, 101))
   141  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 10, name: "p2"}, 10))
   142  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p3"}, 200))
   143  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 3, name: "p4"}, 3))
   144  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 1, name: "p5"}, 1))
   145  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 5, name: "p6"}, 5))
   146  	pq.Push(NewPriorityQueueItem[*employee](&employee{age: 200, name: "p7"}, 201))
   147  
   148  	expectedPriorities := []int64{201, 200, 101, 10, 5, 3, 1, 1}
   149  	for i, priority := range expectedPriorities {
   150  		peekItem := pq.Peek()
   151  		t.Logf("peek item: %v, priority: %d", peekItem.Value(), peekItem.Priority())
   152  		item := pq.Pop()
   153  		t.Logf("%v, priority: %d", item.Value(), item.Priority())
   154  		assert.Equal(t, priority, item.Priority(), "priority", i)
   155  	}
   156  }
   157  
   158  func BenchmarkArrayPriorityQueue_Push(b *testing.B) {
   159  	var list = make([]PQItem[*employee], 0, b.N)
   160  	for i := 0; i < b.N; i++ {
   161  		e := NewPriorityQueueItem[*employee](&employee{age: i, name: fmt.Sprintf("p%d", i)}, int64(i))
   162  		list = append(list, e)
   163  	}
   164  	b.ResetTimer()
   165  	pq := NewArrayPriorityQueue[*employee](
   166  		WithArrayPriorityQueueEnableThreadSafe[*employee](),
   167  		WithArrayPriorityQueueCapacity[*employee](32),
   168  		WithArrayPriorityQueueComparator[*employee](func(i, j ReadOnlyPQItem[*employee]) CmpEnum {
   169  			res := j.Priority() - i.Priority()
   170  			if res > 0 {
   171  				return iGTj
   172  			} else if res < 0 {
   173  				return iLTj
   174  			}
   175  			return iEQj
   176  		}),
   177  	)
   178  	for i := 0; i < b.N; i++ {
   179  		pq.Push(list[i])
   180  	}
   181  	b.ReportAllocs()
   182  }
   183  
   184  func BenchmarkArrayPriorityQueue_Pop(b *testing.B) {
   185  	var list = make([]PQItem[*employee], 0, b.N)
   186  	for i := 0; i < b.N; i++ {
   187  		e := NewPriorityQueueItem[*employee](&employee{age: i, name: fmt.Sprintf("p%d", i)}, int64(i))
   188  		list = append(list, e)
   189  	}
   190  	pq := NewArrayPriorityQueue[*employee](
   191  		WithArrayPriorityQueueEnableThreadSafe[*employee](),
   192  		WithArrayPriorityQueueCapacity[*employee](32),
   193  	)
   194  	for i := 0; i < b.N; i++ {
   195  		pq.Push(list[i])
   196  	}
   197  	b.ResetTimer()
   198  	for i := 0; i < b.N; i++ {
   199  		_ = pq.Pop()
   200  	}
   201  	b.ReportAllocs()
   202  }