test: collection 包完善测试用例

This commit is contained in:
kercylan98 2024-01-11 18:46:10 +08:00
parent 66d903474d
commit e3d966e215
21 changed files with 809 additions and 119 deletions

View File

@ -3,7 +3,7 @@ package activity
import (
"fmt"
"github.com/kercylan98/minotaur/utils/collection"
listings2 "github.com/kercylan98/minotaur/utils/collection/listings"
"github.com/kercylan98/minotaur/utils/collection/listings"
"github.com/kercylan98/minotaur/utils/generic"
"github.com/kercylan98/minotaur/utils/log"
"github.com/kercylan98/minotaur/utils/timer"
@ -22,28 +22,28 @@ type (
)
var (
upcomingEventHandlers map[any]*listings2.PrioritySlice[func(activityId any)] // 即将开始的活动事件处理器
startedEventHandlers map[any]*listings2.PrioritySlice[func(activityId any)] // 活动开始事件处理器
endedEventHandlers map[any]*listings2.PrioritySlice[func(activityId any)] // 活动结束事件处理器
extShowStartedEventHandlers map[any]*listings2.PrioritySlice[func(activityId any)] // 活动结束后延长展示开始事件处理器
extShowEndedEventHandlers map[any]*listings2.PrioritySlice[func(activityId any)] // 活动结束后延长展示结束事件处理器
newDayEventHandlers map[any]*listings2.PrioritySlice[func(activityId any)] // 新的一天事件处理器
upcomingEventHandlers map[any]*listings.PrioritySlice[func(activityId any)] // 即将开始的活动事件处理器
startedEventHandlers map[any]*listings.PrioritySlice[func(activityId any)] // 活动开始事件处理器
endedEventHandlers map[any]*listings.PrioritySlice[func(activityId any)] // 活动结束事件处理器
extShowStartedEventHandlers map[any]*listings.PrioritySlice[func(activityId any)] // 活动结束后延长展示开始事件处理器
extShowEndedEventHandlers map[any]*listings.PrioritySlice[func(activityId any)] // 活动结束后延长展示结束事件处理器
newDayEventHandlers map[any]*listings.PrioritySlice[func(activityId any)] // 新的一天事件处理器
)
func init() {
upcomingEventHandlers = make(map[any]*listings2.PrioritySlice[func(activityId any)])
startedEventHandlers = make(map[any]*listings2.PrioritySlice[func(activityId any)])
endedEventHandlers = make(map[any]*listings2.PrioritySlice[func(activityId any)])
extShowStartedEventHandlers = make(map[any]*listings2.PrioritySlice[func(activityId any)])
extShowEndedEventHandlers = make(map[any]*listings2.PrioritySlice[func(activityId any)])
newDayEventHandlers = make(map[any]*listings2.PrioritySlice[func(activityId any)])
upcomingEventHandlers = make(map[any]*listings.PrioritySlice[func(activityId any)])
startedEventHandlers = make(map[any]*listings.PrioritySlice[func(activityId any)])
endedEventHandlers = make(map[any]*listings.PrioritySlice[func(activityId any)])
extShowStartedEventHandlers = make(map[any]*listings.PrioritySlice[func(activityId any)])
extShowEndedEventHandlers = make(map[any]*listings.PrioritySlice[func(activityId any)])
newDayEventHandlers = make(map[any]*listings.PrioritySlice[func(activityId any)])
}
// RegUpcomingEvent 注册即将开始的活动事件处理器
func RegUpcomingEvent[Type, ID generic.Basic](activityType Type, handler UpcomingEventHandler[ID], priority ...int) {
handlers, exist := upcomingEventHandlers[activityType]
if !exist {
handlers = listings2.NewPrioritySlice[func(activityId any)]()
handlers = listings.NewPrioritySlice[func(activityId any)]()
upcomingEventHandlers[activityType] = handlers
}
handlers.Append(func(activityId any) {
@ -76,7 +76,7 @@ func OnUpcomingEvent[Type, ID generic.Basic](activity *Activity[Type, ID]) {
func RegStartedEvent[Type, ID generic.Basic](activityType Type, handler StartedEventHandler[ID], priority ...int) {
handlers, exist := startedEventHandlers[activityType]
if !exist {
handlers = listings2.NewPrioritySlice[func(activityId any)]()
handlers = listings.NewPrioritySlice[func(activityId any)]()
startedEventHandlers[activityType] = handlers
}
handlers.Append(func(activityId any) {
@ -117,7 +117,7 @@ func OnStartedEvent[Type, ID generic.Basic](activity *Activity[Type, ID]) {
func RegEndedEvent[Type, ID generic.Basic](activityType Type, handler EndedEventHandler[ID], priority ...int) {
handlers, exist := endedEventHandlers[activityType]
if !exist {
handlers = listings2.NewPrioritySlice[func(activityId any)]()
handlers = listings.NewPrioritySlice[func(activityId any)]()
endedEventHandlers[activityType] = handlers
}
handlers.Append(func(activityId any) {
@ -150,7 +150,7 @@ func OnEndedEvent[Type, ID generic.Basic](activity *Activity[Type, ID]) {
func RegExtendedShowStartedEvent[Type, ID generic.Basic](activityType Type, handler ExtendedShowStartedEventHandler[ID], priority ...int) {
handlers, exist := extShowStartedEventHandlers[activityType]
if !exist {
handlers = listings2.NewPrioritySlice[func(activityId any)]()
handlers = listings.NewPrioritySlice[func(activityId any)]()
extShowStartedEventHandlers[activityType] = handlers
}
handlers.Append(func(activityId any) {
@ -183,7 +183,7 @@ func OnExtendedShowStartedEvent[Type, ID generic.Basic](activity *Activity[Type,
func RegExtendedShowEndedEvent[Type, ID generic.Basic](activityType Type, handler ExtendedShowEndedEventHandler[ID], priority ...int) {
handlers, exist := extShowEndedEventHandlers[activityType]
if !exist {
handlers = listings2.NewPrioritySlice[func(activityId any)]()
handlers = listings.NewPrioritySlice[func(activityId any)]()
extShowEndedEventHandlers[activityType] = handlers
}
handlers.Append(func(activityId any) {
@ -216,7 +216,7 @@ func OnExtendedShowEndedEvent[Type, ID generic.Basic](activity *Activity[Type, I
func RegNewDayEvent[Type, ID generic.Basic](activityType Type, handler NewDayEventHandler[ID], priority ...int) {
handlers, exist := newDayEventHandlers[activityType]
if !exist {
handlers = listings2.NewPrioritySlice[func(activityId any)]()
handlers = listings.NewPrioritySlice[func(activityId any)]()
newDayEventHandlers[activityType] = handlers
}
handlers.Append(func(activityId any) {

View File

@ -96,7 +96,7 @@ func (slf *TmplField) handleSlice(fieldName, fieldType string, fields map[string
}
slf.slice = true
t := strings.TrimPrefix(fieldType, "[]")
if collection.FindInMapKey(fields, t) {
if collection.KeyInMap(fields, t) {
slf.Struct = nil
slf.Type = t
} else {

View File

@ -19,7 +19,7 @@ func (slf *TmplStruct) addField(parent, name, desc, fieldType string, fields map
Desc: desc,
Type: fieldType,
}
if !collection.FindInMapKey(fields, fieldType) {
if !collection.KeyInMap(fields, fieldType) {
field.setStruct(parent, name, desc, fieldType, fields)
} else {
field.Type = GetFieldGolangType(fields[fieldType])

View File

@ -3,7 +3,7 @@ package server
import (
"fmt"
"github.com/kercylan98/minotaur/utils/collection"
listings2 "github.com/kercylan98/minotaur/utils/collection/listings"
"github.com/kercylan98/minotaur/utils/collection/listings"
"github.com/kercylan98/minotaur/utils/log"
"github.com/kercylan98/minotaur/utils/runtimes"
"golang.org/x/crypto/ssh/terminal"
@ -43,45 +43,45 @@ type (
func newEvent(srv *Server) *event {
return &event{
Server: srv,
startBeforeEventHandlers: listings2.NewPrioritySlice[StartBeforeEventHandler](),
startFinishEventHandlers: listings2.NewPrioritySlice[StartFinishEventHandler](),
stopEventHandlers: listings2.NewPrioritySlice[StopEventHandler](),
connectionReceivePacketEventHandlers: listings2.NewPrioritySlice[ConnectionReceivePacketEventHandler](),
connectionOpenedEventHandlers: listings2.NewPrioritySlice[ConnectionOpenedEventHandler](),
connectionClosedEventHandlers: listings2.NewPrioritySlice[ConnectionClosedEventHandler](),
messageErrorEventHandlers: listings2.NewPrioritySlice[MessageErrorEventHandler](),
messageLowExecEventHandlers: listings2.NewPrioritySlice[MessageLowExecEventHandler](),
connectionOpenedAfterEventHandlers: listings2.NewPrioritySlice[ConnectionOpenedAfterEventHandler](),
connectionWritePacketBeforeHandlers: listings2.NewPrioritySlice[ConnectionWritePacketBeforeEventHandler](),
shuntChannelCreatedEventHandlers: listings2.NewPrioritySlice[ShuntChannelCreatedEventHandler](),
shuntChannelClosedEventHandlers: listings2.NewPrioritySlice[ShuntChannelClosedEventHandler](),
connectionPacketPreprocessEventHandlers: listings2.NewPrioritySlice[ConnectionPacketPreprocessEventHandler](),
messageExecBeforeEventHandlers: listings2.NewPrioritySlice[MessageExecBeforeEventHandler](),
messageReadyEventHandlers: listings2.NewPrioritySlice[MessageReadyEventHandler](),
deadlockDetectEventHandlers: listings2.NewPrioritySlice[OnDeadlockDetectEventHandler](),
startBeforeEventHandlers: listings.NewPrioritySlice[StartBeforeEventHandler](),
startFinishEventHandlers: listings.NewPrioritySlice[StartFinishEventHandler](),
stopEventHandlers: listings.NewPrioritySlice[StopEventHandler](),
connectionReceivePacketEventHandlers: listings.NewPrioritySlice[ConnectionReceivePacketEventHandler](),
connectionOpenedEventHandlers: listings.NewPrioritySlice[ConnectionOpenedEventHandler](),
connectionClosedEventHandlers: listings.NewPrioritySlice[ConnectionClosedEventHandler](),
messageErrorEventHandlers: listings.NewPrioritySlice[MessageErrorEventHandler](),
messageLowExecEventHandlers: listings.NewPrioritySlice[MessageLowExecEventHandler](),
connectionOpenedAfterEventHandlers: listings.NewPrioritySlice[ConnectionOpenedAfterEventHandler](),
connectionWritePacketBeforeHandlers: listings.NewPrioritySlice[ConnectionWritePacketBeforeEventHandler](),
shuntChannelCreatedEventHandlers: listings.NewPrioritySlice[ShuntChannelCreatedEventHandler](),
shuntChannelClosedEventHandlers: listings.NewPrioritySlice[ShuntChannelClosedEventHandler](),
connectionPacketPreprocessEventHandlers: listings.NewPrioritySlice[ConnectionPacketPreprocessEventHandler](),
messageExecBeforeEventHandlers: listings.NewPrioritySlice[MessageExecBeforeEventHandler](),
messageReadyEventHandlers: listings.NewPrioritySlice[MessageReadyEventHandler](),
deadlockDetectEventHandlers: listings.NewPrioritySlice[OnDeadlockDetectEventHandler](),
}
}
type event struct {
*Server
startBeforeEventHandlers *listings2.PrioritySlice[StartBeforeEventHandler]
startFinishEventHandlers *listings2.PrioritySlice[StartFinishEventHandler]
stopEventHandlers *listings2.PrioritySlice[StopEventHandler]
connectionReceivePacketEventHandlers *listings2.PrioritySlice[ConnectionReceivePacketEventHandler]
connectionOpenedEventHandlers *listings2.PrioritySlice[ConnectionOpenedEventHandler]
connectionClosedEventHandlers *listings2.PrioritySlice[ConnectionClosedEventHandler]
messageErrorEventHandlers *listings2.PrioritySlice[MessageErrorEventHandler]
messageLowExecEventHandlers *listings2.PrioritySlice[MessageLowExecEventHandler]
connectionOpenedAfterEventHandlers *listings2.PrioritySlice[ConnectionOpenedAfterEventHandler]
connectionWritePacketBeforeHandlers *listings2.PrioritySlice[ConnectionWritePacketBeforeEventHandler]
shuntChannelCreatedEventHandlers *listings2.PrioritySlice[ShuntChannelCreatedEventHandler]
shuntChannelClosedEventHandlers *listings2.PrioritySlice[ShuntChannelClosedEventHandler]
connectionPacketPreprocessEventHandlers *listings2.PrioritySlice[ConnectionPacketPreprocessEventHandler]
messageExecBeforeEventHandlers *listings2.PrioritySlice[MessageExecBeforeEventHandler]
messageReadyEventHandlers *listings2.PrioritySlice[MessageReadyEventHandler]
deadlockDetectEventHandlers *listings2.PrioritySlice[OnDeadlockDetectEventHandler]
startBeforeEventHandlers *listings.PrioritySlice[StartBeforeEventHandler]
startFinishEventHandlers *listings.PrioritySlice[StartFinishEventHandler]
stopEventHandlers *listings.PrioritySlice[StopEventHandler]
connectionReceivePacketEventHandlers *listings.PrioritySlice[ConnectionReceivePacketEventHandler]
connectionOpenedEventHandlers *listings.PrioritySlice[ConnectionOpenedEventHandler]
connectionClosedEventHandlers *listings.PrioritySlice[ConnectionClosedEventHandler]
messageErrorEventHandlers *listings.PrioritySlice[MessageErrorEventHandler]
messageLowExecEventHandlers *listings.PrioritySlice[MessageLowExecEventHandler]
connectionOpenedAfterEventHandlers *listings.PrioritySlice[ConnectionOpenedAfterEventHandler]
connectionWritePacketBeforeHandlers *listings.PrioritySlice[ConnectionWritePacketBeforeEventHandler]
shuntChannelCreatedEventHandlers *listings.PrioritySlice[ShuntChannelCreatedEventHandler]
shuntChannelClosedEventHandlers *listings.PrioritySlice[ShuntChannelClosedEventHandler]
connectionPacketPreprocessEventHandlers *listings.PrioritySlice[ConnectionPacketPreprocessEventHandler]
messageExecBeforeEventHandlers *listings.PrioritySlice[MessageExecBeforeEventHandler]
messageReadyEventHandlers *listings.PrioritySlice[MessageReadyEventHandler]
deadlockDetectEventHandlers *listings.PrioritySlice[OnDeadlockDetectEventHandler]
consoleCommandEventHandlers map[string]*listings2.PrioritySlice[ConsoleCommandEventHandler]
consoleCommandEventHandlers map[string]*listings.PrioritySlice[ConsoleCommandEventHandler]
consoleCommandEventHandlerInitOnce sync.Once
}
@ -109,7 +109,7 @@ func (slf *event) RegConsoleCommandEvent(command string, handler ConsoleCommandE
}
slf.consoleCommandEventHandlerInitOnce.Do(func() {
slf.consoleCommandEventHandlers = map[string]*listings2.PrioritySlice[ConsoleCommandEventHandler]{}
slf.consoleCommandEventHandlers = map[string]*listings.PrioritySlice[ConsoleCommandEventHandler]{}
go func() {
for {
var input string
@ -124,7 +124,7 @@ func (slf *event) RegConsoleCommandEvent(command string, handler ConsoleCommandE
})
list, exist := slf.consoleCommandEventHandlers[command]
if !exist {
list = listings2.NewPrioritySlice[ConsoleCommandEventHandler]()
list = listings.NewPrioritySlice[ConsoleCommandEventHandler]()
slf.consoleCommandEventHandlers[command] = list
}
list.Append(handler, collection.FindFirstOrDefaultInSlice(priority, 0))

View File

@ -3,7 +3,7 @@ package gateway
import (
"github.com/kercylan98/minotaur/server"
"github.com/kercylan98/minotaur/utils/collection"
listings2 "github.com/kercylan98/minotaur/utils/collection/listings"
"github.com/kercylan98/minotaur/utils/collection/listings"
)
type (
@ -17,22 +17,22 @@ type (
func newEvents() *events {
return &events{
connectionOpenedEventHandles: listings2.NewPrioritySlice[ConnectionOpenedEventHandle](),
connectionClosedEventHandles: listings2.NewPrioritySlice[ConnectionClosedEventHandle](),
connectionReceivePacketEventHandles: listings2.NewPrioritySlice[ConnectionReceivePacketEventHandle](),
endpointConnectOpenedEventHandles: listings2.NewPrioritySlice[EndpointConnectOpenedEventHandle](),
endpointConnectClosedEventHandles: listings2.NewPrioritySlice[EndpointConnectClosedEventHandle](),
endpointConnectReceivePacketEventHandles: listings2.NewPrioritySlice[EndpointConnectReceivePacketEventHandle](),
connectionOpenedEventHandles: listings.NewPrioritySlice[ConnectionOpenedEventHandle](),
connectionClosedEventHandles: listings.NewPrioritySlice[ConnectionClosedEventHandle](),
connectionReceivePacketEventHandles: listings.NewPrioritySlice[ConnectionReceivePacketEventHandle](),
endpointConnectOpenedEventHandles: listings.NewPrioritySlice[EndpointConnectOpenedEventHandle](),
endpointConnectClosedEventHandles: listings.NewPrioritySlice[EndpointConnectClosedEventHandle](),
endpointConnectReceivePacketEventHandles: listings.NewPrioritySlice[EndpointConnectReceivePacketEventHandle](),
}
}
type events struct {
connectionOpenedEventHandles *listings2.PrioritySlice[ConnectionOpenedEventHandle]
connectionClosedEventHandles *listings2.PrioritySlice[ConnectionClosedEventHandle]
connectionReceivePacketEventHandles *listings2.PrioritySlice[ConnectionReceivePacketEventHandle]
endpointConnectOpenedEventHandles *listings2.PrioritySlice[EndpointConnectOpenedEventHandle]
endpointConnectClosedEventHandles *listings2.PrioritySlice[EndpointConnectClosedEventHandle]
endpointConnectReceivePacketEventHandles *listings2.PrioritySlice[EndpointConnectReceivePacketEventHandle]
connectionOpenedEventHandles *listings.PrioritySlice[ConnectionOpenedEventHandle]
connectionClosedEventHandles *listings.PrioritySlice[ConnectionClosedEventHandle]
connectionReceivePacketEventHandles *listings.PrioritySlice[ConnectionReceivePacketEventHandle]
endpointConnectOpenedEventHandles *listings.PrioritySlice[EndpointConnectOpenedEventHandle]
endpointConnectClosedEventHandles *listings.PrioritySlice[EndpointConnectClosedEventHandle]
endpointConnectReceivePacketEventHandles *listings.PrioritySlice[EndpointConnectReceivePacketEventHandle]
}
// RegConnectionOpenedEventHandle 注册客户端连接打开事件处理函数

View File

@ -70,7 +70,7 @@ type (
// HasMessageType 检查是否存在指定的消息类型
func HasMessageType(mt MessageType) bool {
return collection.FindInMapKey(messageNames, mt)
return collection.KeyInMap(messageNames, mt)
}
// Message 服务器消息

View File

@ -57,7 +57,7 @@ func GetNetworks() []Network {
// check 检查网络模式是否支持
func (n Network) check() {
if !collection.FindInMapKey(networkNameMap, string(n)) {
if !collection.KeyInMap(networkNameMap, string(n)) {
panic(fmt.Errorf("unsupported network mode: %s", n))
}
}

View File

@ -45,7 +45,7 @@ func (slf *Area[ID, AreaInfo]) IsAllow(item Item[ID]) (constraintErr error, conf
// IsConflict 检测一个成员是否会造成冲突
func (slf *Area[ID, AreaInfo]) IsConflict(item Item[ID]) bool {
if collection.FindInMapKey(slf.items, item.GetID()) {
if collection.KeyInMap(slf.items, item.GetID()) {
return false
}
for _, conflict := range slf.conflicts {
@ -58,7 +58,7 @@ func (slf *Area[ID, AreaInfo]) IsConflict(item Item[ID]) bool {
// GetConflictItems 获取与一个成员产生冲突的所有其他成员
func (slf *Area[ID, AreaInfo]) GetConflictItems(item Item[ID]) map[ID]Item[ID] {
if collection.FindInMapKey(slf.items, item.GetID()) {
if collection.KeyInMap(slf.items, item.GetID()) {
return nil
}
var conflictItems map[ID]Item[ID]

View File

@ -32,7 +32,7 @@ func (slf *Editor[ID, AreaInfo]) RemoveAreaItem(area *Area[ID, AreaInfo], item I
// AddAreaItem 将一个成员添加到编排区域中,如果该成员已经存在于编排区域中,则不进行任何操作
func (slf *Editor[ID, AreaInfo]) AddAreaItem(area *Area[ID, AreaInfo], item Item[ID]) {
if collection.FindInMapKey(slf.falls, item.GetID()) {
if collection.KeyInMap(slf.falls, item.GetID()) {
return
}
area.items[item.GetID()] = item

View File

@ -0,0 +1,6 @@
package collection
import "github.com/kercylan98/minotaur/utils/generic"
type ComparisonHandler[V any] func(source, target V) bool
type OrderedValueGetter[V any, N generic.Ordered] func(v V) N

View File

@ -1,7 +1,5 @@
package collection
type ComparisonHandler[V any] func(source, target V) bool
// InSlice 检查 v 是否被包含在 slice 中,当 handler 返回 true 时,表示 v 和 slice 中的某个元素相匹配
func InSlice[S ~[]V, V any](slice S, v V, handler ComparisonHandler[V]) bool {
if len(slice) == 0 {

View File

@ -1,6 +1,8 @@
package collection
import "github.com/kercylan98/minotaur/utils/generic"
import (
"github.com/kercylan98/minotaur/utils/generic"
)
// FindLoopedNextInSlice 返回 i 的下一个数组成员,当 i 达到数组长度时从 0 开始
// - 当 i 为负数时将返回第一个元素
@ -143,32 +145,42 @@ func FindIndexInComparableSlice[S ~[]V, V comparable](slice S, v V) int {
return -1
}
// FindInSliceByBinary 判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则索引返回 -1
func FindInSliceByBinary[S ~[]V, V any](slice S, handler func(v V) bool) (i int, t V) {
low := 0
high := len(slice) - 1
for low <= high {
mid := low + (high-low)/2
if handler(slice[mid]) {
return mid, slice[mid]
} else if handler(slice[mid]) {
high = mid - 1
} else {
low = mid + 1
}
}
return -1, t
}
// FindMinimumInSlice 获取切片中的最小值
func FindMinimumInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHandler[V]) (result V) {
// FindMinimumInComparableSlice 获取切片中的最小值
func FindMinimumInComparableSlice[S ~[]V, V generic.Ordered](slice S) (result V) {
if len(slice) == 0 {
return
}
result = slice[0]
for i := 1; i < len(slice); i++ {
if handler(slice[i], result) {
if result > slice[i] {
result = slice[i]
}
}
return
}
// FindMinimumInSlice 获取切片中的最小值
func FindMinimumInSlice[S ~[]V, V any, N generic.Ordered](slice S, handler OrderedValueGetter[V, N]) (result V) {
if len(slice) == 0 {
return
}
result = slice[0]
for i := 1; i < len(slice); i++ {
if handler(result) > handler(slice[i]) {
result = slice[i]
}
}
return
}
// FindMaximumInComparableSlice 获取切片中的最大值
func FindMaximumInComparableSlice[S ~[]V, V generic.Ordered](slice S) (result V) {
if len(slice) == 0 {
return
}
result = slice[0]
for i := 1; i < len(slice); i++ {
if result < slice[i] {
result = slice[i]
}
}
@ -176,44 +188,100 @@ func FindMinimumInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHan
}
// FindMaximumInSlice 获取切片中的最大值
func FindMaximumInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHandler[V]) (result V) {
func FindMaximumInSlice[S ~[]V, V any, N generic.Ordered](slice S, handler OrderedValueGetter[V, N]) (result V) {
if len(slice) == 0 {
return
}
result = slice[0]
for i := 1; i < len(slice); i++ {
if handler(result, slice[i]) {
if handler(result) < handler(slice[i]) {
result = slice[i]
}
}
return
}
// FindMin2MaxInSlice 获取切片中的最小值和最大值
func FindMin2MaxInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHandler[V]) (min, max V) {
// FindMin2MaxInComparableSlice 获取切片中的最小值和最大值
func FindMin2MaxInComparableSlice[S ~[]V, V generic.Ordered](slice S) (min, max V) {
if len(slice) == 0 {
return
}
min = slice[0]
max = slice[0]
for i := 1; i < len(slice); i++ {
if handler(slice[i], min) {
if min > slice[i] {
min = slice[i]
}
if handler(max, slice[i]) {
if max < slice[i] {
max = slice[i]
}
}
return
}
// FindMin2MaxInSlice 获取切片中的最小值和最大值
func FindMin2MaxInSlice[S ~[]V, V any, N generic.Ordered](slice S, handler OrderedValueGetter[V, N]) (min, max V) {
if len(slice) == 0 {
return
}
min = slice[0]
max = slice[0]
for i := 1; i < len(slice); i++ {
if handler(min) > handler(slice[i]) {
min = slice[i]
}
if handler(max) < handler(slice[i]) {
max = slice[i]
}
}
return
}
// FindMinFromComparableMap 获取 map 中的最小值
func FindMinFromComparableMap[M ~map[K]V, K comparable, V generic.Ordered](m M) (result V) {
if m == nil {
return
}
var first bool
for _, v := range m {
if !first {
result = v
first = true
continue
}
if result > v {
result = v
}
}
return
}
// FindMinFromMap 获取 map 中的最小值
func FindMinFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler ComparisonHandler[V]) (result V) {
func FindMinFromMap[M ~map[K]V, K comparable, V any, N generic.Ordered](m M, handler OrderedValueGetter[V, N]) (result V) {
if m == nil {
return
}
var first bool
for _, v := range m {
if !first {
result = v
first = true
continue
}
if handler(result) > handler(v) {
result = v
}
}
return
}
// FindMaxFromComparableMap 获取 map 中的最大值
func FindMaxFromComparableMap[M ~map[K]V, K comparable, V generic.Ordered](m M) (result V) {
if m == nil {
return
}
for _, v := range m {
if handler(v, result) {
if result < v {
result = v
}
}
@ -221,36 +289,60 @@ func FindMinFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler Com
}
// FindMaxFromMap 获取 map 中的最大值
func FindMaxFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler ComparisonHandler[V]) (result V) {
func FindMaxFromMap[M ~map[K]V, K comparable, V any, N generic.Ordered](m M, handler OrderedValueGetter[V, N]) (result V) {
if m == nil {
return
}
for _, v := range m {
if handler(result, v) {
if handler(result) < handler(v) {
result = v
}
}
return
}
// FindMin2MaxFromMap 获取 map 中的最小值和最大值
func FindMin2MaxFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler ComparisonHandler[V]) (min, max V) {
// FindMin2MaxFromComparableMap 获取 map 中的最小值和最大值
func FindMin2MaxFromComparableMap[M ~map[K]V, K comparable, V generic.Ordered](m M) (min, max V) {
if m == nil {
return
}
var first bool
for _, v := range m {
if handler(v, min) {
if !first {
min = v
max = v
first = true
continue
}
if min > v {
min = v
}
if handler(max, v) {
if max < v {
max = v
}
}
return
}
// FindInMapKey 判断 map 中是否存在某个 key
func FindInMapKey[M ~map[K]V, K comparable, V any](m M, k K) bool {
_, exist := m[k]
return exist
// FindMin2MaxFromMap 获取 map 中的最小值和最大值
func FindMin2MaxFromMap[M ~map[K]V, K comparable, V generic.Ordered](m M) (min, max V) {
if m == nil {
return
}
var first bool
for _, v := range m {
if !first {
min = v
max = v
first = true
continue
}
if min > v {
min = v
}
if max < v {
max = v
}
}
return
}

View File

@ -48,3 +48,129 @@ func ExampleFindOrDefaultInComparableSlice() {
// Output:
// 2
}
func ExampleFindInSlice() {
_, result := collection.FindInSlice([]int{1, 2, 3}, func(v int) bool {
return v == 2
})
fmt.Println(result)
// Output:
// 2
}
func ExampleFindIndexInSlice() {
result := collection.FindIndexInSlice([]int{1, 2, 3}, func(v int) bool {
return v == 2
})
fmt.Println(result)
// Output:
// 1
}
func ExampleFindInComparableSlice() {
index, result := collection.FindInComparableSlice([]int{1, 2, 3}, 2)
fmt.Println(index, result)
// Output:
// 1 2
}
func ExampleFindIndexInComparableSlice() {
result := collection.FindIndexInComparableSlice([]int{1, 2, 3}, 2)
fmt.Println(result)
// Output:
// 1
}
func ExampleFindMinimumInComparableSlice() {
result := collection.FindMinimumInComparableSlice([]int{1, 2, 3})
fmt.Println(result)
// Output:
// 1
}
func ExampleFindMinimumInSlice() {
result := collection.FindMinimumInSlice([]int{1, 2, 3}, func(v int) int {
return v
})
fmt.Println(result)
// Output:
// 1
}
func ExampleFindMaximumInComparableSlice() {
result := collection.FindMaximumInComparableSlice([]int{1, 2, 3})
fmt.Println(result)
// Output:
// 3
}
func ExampleFindMaximumInSlice() {
result := collection.FindMaximumInSlice([]int{1, 2, 3}, func(v int) int {
return v
})
fmt.Println(result)
// Output:
// 3
}
func ExampleFindMin2MaxInComparableSlice() {
minimum, maximum := collection.FindMin2MaxInComparableSlice([]int{1, 2, 3})
fmt.Println(minimum, maximum)
// Output:
// 1 3
}
func ExampleFindMin2MaxInSlice() {
minimum, maximum := collection.FindMin2MaxInSlice([]int{1, 2, 3}, func(v int) int {
return v
})
fmt.Println(minimum, maximum)
// Output:
// 1 3
}
func ExampleFindMinFromComparableMap() {
result := collection.FindMinFromComparableMap(map[int]int{1: 1, 2: 2, 3: 3})
fmt.Println(result)
// Output:
// 1
}
func ExampleFindMinFromMap() {
result := collection.FindMinFromMap(map[int]int{1: 1, 2: 2, 3: 3}, func(v int) int {
return v
})
fmt.Println(result)
// Output:
// 1
}
func ExampleFindMaxFromComparableMap() {
result := collection.FindMaxFromComparableMap(map[int]int{1: 1, 2: 2, 3: 3})
fmt.Println(result)
// Output:
// 3
}
func ExampleFindMaxFromMap() {
result := collection.FindMaxFromMap(map[int]int{1: 1, 2: 2, 3: 3}, func(v int) int {
return v
})
fmt.Println(result)
// Output:
// 3
}
func ExampleFindMin2MaxFromComparableMap() {
minimum, maximum := collection.FindMin2MaxFromComparableMap(map[int]int{1: 1, 2: 2, 3: 3})
fmt.Println(minimum, maximum)
// Output:
// 1 3
}
func ExampleFindMin2MaxFromMap() {
minimum, maximum := collection.FindMin2MaxFromMap(map[int]int{1: 1, 2: 2, 3: 3})
fmt.Println(minimum, maximum)
// Output:
// 1 3
}

View File

@ -127,3 +127,341 @@ func TestFindOrDefaultInComparableSlice(t *testing.T) {
})
}
}
func TestFindInSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindInSlice_NonEmptySlice", []int{1, 2, 3}, 2},
{"TestFindInSlice_EmptySlice", []int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
_, actual := collection.FindInSlice(c.input, func(v int) bool {
return v == 2
})
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the element of input is not equal")
}
})
}
}
func TestFindIndexInSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindIndexInSlice_NonEmptySlice", []int{1, 2, 3}, 1},
{"TestFindIndexInSlice_EmptySlice", []int{}, -1},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindIndexInSlice(c.input, func(v int) bool {
return v == 2
})
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the index of input is not equal")
}
})
}
}
func TestFindInComparableSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindInComparableSlice_NonEmptySlice", []int{1, 2, 3}, 2},
{"TestFindInComparableSlice_EmptySlice", []int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
_, actual := collection.FindInComparableSlice(c.input, 2)
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the element of input is not equal")
}
})
}
}
func TestFindIndexInComparableSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindIndexInComparableSlice_NonEmptySlice", []int{1, 2, 3}, 1},
{"TestFindIndexInComparableSlice_EmptySlice", []int{}, -1},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindIndexInComparableSlice(c.input, 2)
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the index of input is not equal")
}
})
}
}
func TestFindMinimumInComparableSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindMinimumInComparableSlice_NonEmptySlice", []int{1, 2, 3}, 1},
{"TestFindMinimumInComparableSlice_EmptySlice", []int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMinimumInComparableSlice(c.input)
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the minimum of input is not equal")
}
})
}
}
func TestFindMinimumInSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindMinimumInSlice_NonEmptySlice", []int{1, 2, 3}, 1},
{"TestFindMinimumInSlice_EmptySlice", []int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMinimumInSlice(c.input, func(v int) int {
return v
})
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the minimum of input is not equal")
}
})
}
}
func TestFindMaximumInComparableSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindMaximumInComparableSlice_NonEmptySlice", []int{1, 2, 3}, 3},
{"TestFindMaximumInComparableSlice_EmptySlice", []int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMaximumInComparableSlice(c.input)
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the maximum of input is not equal")
}
})
}
}
func TestFindMaximumInSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected int
}{
{"TestFindMaximumInSlice_NonEmptySlice", []int{1, 2, 3}, 3},
{"TestFindMaximumInSlice_EmptySlice", []int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMaximumInSlice(c.input, func(v int) int {
return v
})
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the maximum of input is not equal")
}
})
}
}
func TestFindMin2MaxInComparableSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expectedMin int
expectedMax int
}{
{"TestFindMin2MaxInComparableSlice_NonEmptySlice", []int{1, 2, 3}, 1, 3},
{"TestFindMin2MaxInComparableSlice_EmptySlice", []int{}, 0, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
minimum, maximum := collection.FindMin2MaxInComparableSlice(c.input)
if minimum != c.expectedMin || maximum != c.expectedMax {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expectedMin, minimum, "the minimum of input is not equal")
}
})
}
}
func TestFindMin2MaxInSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expectedMin int
expectedMax int
}{
{"TestFindMin2MaxInSlice_NonEmptySlice", []int{1, 2, 3}, 1, 3},
{"TestFindMin2MaxInSlice_EmptySlice", []int{}, 0, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
minimum, maximum := collection.FindMin2MaxInSlice(c.input, func(v int) int {
return v
})
if minimum != c.expectedMin || maximum != c.expectedMax {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expectedMin, minimum, "the minimum of input is not equal")
}
})
}
}
func TestFindMinFromComparableMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expected int
}{
{"TestFindMinFromComparableMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, 1},
{"TestFindMinFromComparableMap_EmptyMap", map[int]int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMinFromComparableMap(c.input)
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the minimum of input is not equal")
}
})
}
}
func TestFindMinFromMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expected int
}{
{"TestFindMinFromMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, 1},
{"TestFindMinFromMap_EmptyMap", map[int]int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMinFromMap(c.input, func(v int) int {
return v
})
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the minimum of input is not equal")
}
})
}
}
func TestFindMaxFromComparableMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expected int
}{
{"TestFindMaxFromComparableMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, 3},
{"TestFindMaxFromComparableMap_EmptyMap", map[int]int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMaxFromComparableMap(c.input)
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the maximum of input is not equal")
}
})
}
}
func TestFindMaxFromMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expected int
}{
{"TestFindMaxFromMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, 3},
{"TestFindMaxFromMap_EmptyMap", map[int]int{}, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
actual := collection.FindMaxFromMap(c.input, func(v int) int {
return v
})
if actual != c.expected {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "the maximum of input is not equal")
}
})
}
}
func TestFindMin2MaxFromComparableMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expectedMin int
expectedMax int
}{
{"TestFindMin2MaxFromComparableMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, 1, 3},
{"TestFindMin2MaxFromComparableMap_EmptyMap", map[int]int{}, 0, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
minimum, maximum := collection.FindMin2MaxFromComparableMap(c.input)
if minimum != c.expectedMin || maximum != c.expectedMax {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expectedMin, minimum, "the minimum of input is not equal")
}
})
}
}
func TestFindMin2MaxFromMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expectedMin int
expectedMax int
}{
{"TestFindMin2MaxFromMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, 1, 3},
{"TestFindMin2MaxFromMap_EmptyMap", map[int]int{}, 0, 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
minimum, maximum := collection.FindMin2MaxFromMap(c.input)
if minimum != c.expectedMin || maximum != c.expectedMax {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expectedMin, minimum, "the minimum of input is not equal")
}
})
}
}

View File

@ -2,5 +2,8 @@ package collection
// SwapSlice 将切片中的两个元素进行交换
func SwapSlice[S ~[]V, V any](slice *S, i, j int) {
if i < 0 || j < 0 || i >= len(*slice) || j >= len(*slice) {
return
}
(*slice)[i], (*slice)[j] = (*slice)[j], (*slice)[i]
}

View File

@ -0,0 +1,14 @@
package collection_test
import (
"fmt"
"github.com/kercylan98/minotaur/utils/collection"
)
func ExampleSwapSlice() {
var s = []int{1, 2, 3}
collection.SwapSlice(&s, 0, 1)
fmt.Println(s)
// Output:
// [2 1 3]
}

View File

@ -0,0 +1,32 @@
package collection_test
import (
"github.com/kercylan98/minotaur/utils/collection"
"testing"
)
func TestSwapSlice(t *testing.T) {
var cases = []struct {
name string
slice []int
i int
j int
expect []int
}{
{"TestSwapSliceNonEmpty", []int{1, 2, 3}, 0, 1, []int{2, 1, 3}},
{"TestSwapSliceEmpty", []int{}, 0, 0, []int{}},
{"TestSwapSliceIndexOutOfBound", []int{1, 2, 3}, 0, 3, []int{1, 2, 3}},
{"TestSwapSliceNil", nil, 0, 0, nil},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
collection.SwapSlice(&c.slice, c.i, c.j)
for i, v := range c.slice {
if v != c.expect[i] {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expect, c.slice, "the slice is not equal")
}
}
})
}
}

View File

@ -0,0 +1,21 @@
package collection
import "fmt"
func ExampleMappingFromSlice() {
result := MappingFromSlice[[]int, []int]([]int{1, 2, 3}, func(value int) int {
return value + 1
})
fmt.Println(result)
// Output:
// [2 3 4]
}
func ExampleMappingFromMap() {
result := MappingFromMap[map[int]int, map[int]int](map[int]int{1: 1, 2: 2, 3: 3}, func(value int) int {
return value + 1
})
fmt.Println(result)
// Output:
// map[1:2 2:3 3:4]
}

View File

@ -0,0 +1,60 @@
package collection_test
import (
"github.com/kercylan98/minotaur/utils/collection"
"testing"
)
func TestMappingFromSlice(t *testing.T) {
var cases = []struct {
name string
input []int
expected []int
}{
{"TestMappingFromSlice_NonEmptySlice", []int{1, 2, 3}, []int{2, 3, 4}},
{"TestMappingFromSlice_EmptySlice", []int{}, []int{}},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
result := collection.MappingFromSlice[[]int, []int](c.input, func(value int) int {
return value + 1
})
if len(result) != len(c.expected) {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, result, "the length of input is not equal")
}
for i := 0; i < len(result); i++ {
if result[i] != c.expected[i] {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, result, "the value of input is not equal")
}
}
})
}
}
func TestMappingFromMap(t *testing.T) {
var cases = []struct {
name string
input map[int]int
expected map[int]int
}{
{"TestMappingFromMap_NonEmptyMap", map[int]int{1: 1, 2: 2, 3: 3}, map[int]int{1: 2, 2: 3, 3: 4}},
{"TestMappingFromMap_EmptyMap", map[int]int{}, map[int]int{}},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
result := collection.MappingFromMap[map[int]int, map[int]int](c.input, func(value int) int {
return value + 1
})
if len(result) != len(c.expected) {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, result, "the length of input is not equal")
}
for k, v := range result {
if v != c.expected[k] {
t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, result, "the value of input is not equal")
}
}
})
}
}

View File

@ -20,7 +20,7 @@ type Deck[I Item] struct {
// AddGroup 将一个组添加到甲板中
func (slf *Deck[I]) AddGroup(group *Group[I]) {
if !collection.FindInMapKey(slf.groups, group.GetGuid()) {
if !collection.KeyInMap(slf.groups, group.GetGuid()) {
slf.groups[group.GetGuid()] = group
slf.sort = append(slf.sort, group.GetGuid())
}

View File

@ -60,7 +60,7 @@ func (slf *FSM[State, Data]) Unregister(state State) {
// HasState 检查状态机是否存在特定状态
func (slf *FSM[State, Data]) HasState(state State) bool {
return collection.FindInMapKey(slf.states, state)
return collection.KeyInMap(slf.states, state)
}
// Change 改变状态机状态到新的状态