diff --git a/container/garray/garray_normal_any.go b/container/garray/garray_normal_any.go index 78d7ae4a8..e67c20b3d 100644 --- a/container/garray/garray_normal_any.go +++ b/container/garray/garray_normal_any.go @@ -233,13 +233,26 @@ func (a *Array) doRemoveWithoutLock(index int) (value interface{}, found bool) { // RemoveValue removes an item by value. // It returns true if value is found in the array, or else false if not found. func (a *Array) RemoveValue(value interface{}) bool { - if i := a.Search(value); i != -1 { - a.Remove(i) + a.mu.Lock() + defer a.mu.Unlock() + if i := a.doSearchWithoutLock(value); i != -1 { + a.doRemoveWithoutLock(i) return true } return false } +// RemoveValues removes multiple items by `values`. +func (a *Array) RemoveValues(values ...interface{}) { + a.mu.Lock() + defer a.mu.Unlock() + for _, value := range values { + if i := a.doSearchWithoutLock(value); i != -1 { + a.doRemoveWithoutLock(i) + } + } +} + // PushLeft pushes one or multiple items to the beginning of array. func (a *Array) PushLeft(value ...interface{}) *Array { a.mu.Lock() @@ -487,6 +500,10 @@ func (a *Array) Contains(value interface{}) bool { func (a *Array) Search(value interface{}) int { a.mu.RLock() defer a.mu.RUnlock() + return a.doSearchWithoutLock(value) +} + +func (a *Array) doSearchWithoutLock(value interface{}) int { if len(a.array) == 0 { return -1 } diff --git a/container/garray/garray_normal_int.go b/container/garray/garray_normal_int.go index e44ed0766..5feb2fe28 100644 --- a/container/garray/garray_normal_int.go +++ b/container/garray/garray_normal_int.go @@ -228,13 +228,26 @@ func (a *IntArray) doRemoveWithoutLock(index int) (value int, found bool) { // RemoveValue removes an item by value. // It returns true if value is found in the array, or else false if not found. func (a *IntArray) RemoveValue(value int) bool { - if i := a.Search(value); i != -1 { - _, found := a.Remove(i) - return found + a.mu.Lock() + defer a.mu.Unlock() + if i := a.doSearchWithoutLock(value); i != -1 { + a.doRemoveWithoutLock(i) + return true } return false } +// RemoveValues removes multiple items by `values`. +func (a *IntArray) RemoveValues(values ...int) { + a.mu.Lock() + defer a.mu.Unlock() + for _, value := range values { + if i := a.doSearchWithoutLock(value); i != -1 { + a.doRemoveWithoutLock(i) + } + } +} + // PushLeft pushes one or multiple items to the beginning of array. func (a *IntArray) PushLeft(value ...int) *IntArray { a.mu.Lock() @@ -497,6 +510,10 @@ func (a *IntArray) Contains(value int) bool { func (a *IntArray) Search(value int) int { a.mu.RLock() defer a.mu.RUnlock() + return a.doSearchWithoutLock(value) +} + +func (a *IntArray) doSearchWithoutLock(value int) int { if len(a.array) == 0 { return -1 } diff --git a/container/garray/garray_normal_str.go b/container/garray/garray_normal_str.go index 8b3f8f280..8af6bd97d 100644 --- a/container/garray/garray_normal_str.go +++ b/container/garray/garray_normal_str.go @@ -222,6 +222,17 @@ func (a *StrArray) RemoveValue(value string) bool { return false } +// RemoveValues removes multiple items by `values`. +func (a *StrArray) RemoveValues(values ...string) { + a.mu.Lock() + defer a.mu.Unlock() + for _, value := range values { + if i := a.doSearchWithoutLock(value); i != -1 { + a.doRemoveWithoutLock(i) + } + } +} + // PushLeft pushes one or multiple items to the beginning of array. func (a *StrArray) PushLeft(value ...string) *StrArray { a.mu.Lock() @@ -499,6 +510,10 @@ func (a *StrArray) ContainsI(value string) bool { func (a *StrArray) Search(value string) int { a.mu.RLock() defer a.mu.RUnlock() + return a.doSearchWithoutLock(value) +} + +func (a *StrArray) doSearchWithoutLock(value string) int { if len(a.array) == 0 { return -1 } diff --git a/container/garray/garray_sorted_any.go b/container/garray/garray_sorted_any.go index 494c07e31..f11757f4a 100644 --- a/container/garray/garray_sorted_any.go +++ b/container/garray/garray_sorted_any.go @@ -216,6 +216,17 @@ func (a *SortedArray) RemoveValue(value interface{}) bool { return false } +// RemoveValues removes an item by `values`. +func (a *SortedArray) RemoveValues(values ...interface{}) { + a.mu.Lock() + defer a.mu.Unlock() + for _, value := range values { + if i, r := a.binSearch(value, false); r == 0 { + a.doRemoveWithoutLock(i) + } + } +} + // PopLeft pops and returns an item from the beginning of array. // Note that if the array is empty, the `found` is false. func (a *SortedArray) PopLeft() (value interface{}, found bool) { @@ -470,7 +481,7 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result // SetUnique sets unique mark to the array, // which means it does not contain any repeated items. -// It also do unique check, remove all repeated items. +// It also does unique check, remove all repeated items. func (a *SortedArray) SetUnique(unique bool) *SortedArray { oldUnique := a.unique a.unique = unique diff --git a/container/garray/garray_sorted_int.go b/container/garray/garray_sorted_int.go index aeee26baa..2190830ac 100644 --- a/container/garray/garray_sorted_int.go +++ b/container/garray/garray_sorted_int.go @@ -202,6 +202,17 @@ func (a *SortedIntArray) RemoveValue(value int) bool { return false } +// RemoveValues removes an item by `values`. +func (a *SortedIntArray) RemoveValues(values ...int) { + a.mu.Lock() + defer a.mu.Unlock() + for _, value := range values { + if i, r := a.binSearch(value, false); r == 0 { + a.doRemoveWithoutLock(i) + } + } +} + // PopLeft pops and returns an item from the beginning of array. // Note that if the array is empty, the `found` is false. func (a *SortedIntArray) PopLeft() (value int, found bool) { diff --git a/container/garray/garray_sorted_str.go b/container/garray/garray_sorted_str.go index 3dbd8d8f4..3735e7587 100644 --- a/container/garray/garray_sorted_str.go +++ b/container/garray/garray_sorted_str.go @@ -188,6 +188,17 @@ func (a *SortedStrArray) RemoveValue(value string) bool { return false } +// RemoveValues removes an item by `values`. +func (a *SortedStrArray) RemoveValues(values ...string) { + a.mu.Lock() + defer a.mu.Unlock() + for _, value := range values { + if i, r := a.binSearch(value, false); r == 0 { + a.doRemoveWithoutLock(i) + } + } +} + // PopLeft pops and returns an item from the beginning of array. // Note that if the array is empty, the `found` is false. func (a *SortedStrArray) PopLeft() (value string, found bool) { diff --git a/container/garray/garray_z_unit_normal_any_test.go b/container/garray/garray_z_unit_normal_any_test.go index bacfe2556..c5be6f918 100644 --- a/container/garray/garray_z_unit_normal_any_test.go +++ b/container/garray/garray_z_unit_normal_any_test.go @@ -750,6 +750,15 @@ func TestArray_RemoveValue(t *testing.T) { }) } +func TestArray_RemoveValues(t *testing.T) { + slice := g.Slice{"a", "b", "d", "c"} + array := garray.NewArrayFrom(slice) + gtest.C(t, func(t *gtest.T) { + array.RemoveValues("a", "b", "c") + t.Assert(array.Slice(), g.Slice{"d"}) + }) +} + func TestArray_UnmarshalValue(t *testing.T) { type V struct { Name string diff --git a/container/garray/garray_z_unit_normal_int_test.go b/container/garray/garray_z_unit_normal_int_test.go index 90dcc0461..6c843bbd1 100644 --- a/container/garray/garray_z_unit_normal_int_test.go +++ b/container/garray/garray_z_unit_normal_int_test.go @@ -765,6 +765,15 @@ func TestIntArray_RemoveValue(t *testing.T) { }) } +func TestIntArray_RemoveValues(t *testing.T) { + slice := g.SliceInt{10, 20, 30, 40} + array := garray.NewIntArrayFrom(slice) + gtest.C(t, func(t *gtest.T) { + array.RemoveValues(10, 20, 40) + t.Assert(array.Slice(), g.SliceInt{30}) + }) +} + func TestIntArray_UnmarshalValue(t *testing.T) { type V struct { Name string diff --git a/container/garray/garray_z_unit_normal_str_test.go b/container/garray/garray_z_unit_normal_str_test.go index a6da223c3..f815ed557 100644 --- a/container/garray/garray_z_unit_normal_str_test.go +++ b/container/garray/garray_z_unit_normal_str_test.go @@ -776,6 +776,15 @@ func TestStrArray_RemoveValue(t *testing.T) { }) } +func TestStrArray_RemoveValues(t *testing.T) { + slice := g.SliceStr{"a", "b", "d", "c"} + array := garray.NewStrArrayFrom(slice) + gtest.C(t, func(t *gtest.T) { + array.RemoveValues("a", "b", "c") + t.Assert(array.Slice(), g.SliceStr{"d"}) + }) +} + func TestStrArray_UnmarshalValue(t *testing.T) { type V struct { Name string diff --git a/container/garray/garray_z_unit_sorted_any_test.go b/container/garray/garray_z_unit_sorted_any_test.go index 5af1ed2f9..014e42dfb 100644 --- a/container/garray/garray_z_unit_sorted_any_test.go +++ b/container/garray/garray_z_unit_sorted_any_test.go @@ -869,6 +869,15 @@ func TestSortedArray_RemoveValue(t *testing.T) { }) } +func TestSortedArray_RemoveValues(t *testing.T) { + slice := g.Slice{"a", "b", "d", "c"} + array := garray.NewSortedArrayFrom(slice, gutil.ComparatorString) + gtest.C(t, func(t *gtest.T) { + array.RemoveValues("a", "b", "c") + t.Assert(array.Slice(), g.SliceStr{"d"}) + }) +} + func TestSortedArray_UnmarshalValue(t *testing.T) { type V struct { Name string diff --git a/container/garray/garray_z_unit_sorted_int_test.go b/container/garray/garray_z_unit_sorted_int_test.go index 658fe4b25..c52310a33 100644 --- a/container/garray/garray_z_unit_sorted_int_test.go +++ b/container/garray/garray_z_unit_sorted_int_test.go @@ -737,6 +737,15 @@ func TestSortedIntArray_RemoveValue(t *testing.T) { }) } +func TestSortedIntArray_RemoveValues(t *testing.T) { + slice := g.SliceInt{10, 20, 30, 40} + array := garray.NewSortedIntArrayFrom(slice) + gtest.C(t, func(t *gtest.T) { + array.RemoveValues(10, 40, 20) + t.Assert(array.Slice(), g.SliceInt{30}) + }) +} + func TestSortedIntArray_UnmarshalValue(t *testing.T) { type V struct { Name string diff --git a/container/garray/garray_z_unit_sorted_str_test.go b/container/garray/garray_z_unit_sorted_str_test.go index 65972d056..0fe6e63f2 100644 --- a/container/garray/garray_z_unit_sorted_str_test.go +++ b/container/garray/garray_z_unit_sorted_str_test.go @@ -749,6 +749,15 @@ func TestSortedStrArray_RemoveValue(t *testing.T) { }) } +func TestSortedStrArray_RemoveValues(t *testing.T) { + slice := g.SliceStr{"a", "b", "d", "c"} + array := garray.NewSortedStrArrayFrom(slice) + gtest.C(t, func(t *gtest.T) { + array.RemoveValues("a", "b", "c") + t.Assert(array.Slice(), g.SliceStr{"d"}) + }) +} + func TestSortedStrArray_UnmarshalValue(t *testing.T) { type V struct { Name string