Skip to content

Commit

Permalink
[collections] Added Conditions type to provide a helper to deal…
Browse files Browse the repository at this point in the history
… with flags or boolean slices (#549)

<!--
Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors.
All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->
### Description

- helpers for evaluating flags



### Test Coverage

<!--
Please put an `x` in the correct box e.g. `[x]` to indicate the testing
coverage of this change.
-->

- [x]  This change is covered by existing or additional automated tests.
- [ ] Manual testing has been performed (and evidence provided) as
automated testing was not feasible.
- [ ] Additional tests are not required for this change (e.g.
documentation update).
  • Loading branch information
acabarbaye authored Jan 13, 2025
1 parent 7715438 commit 6531ccd
Show file tree
Hide file tree
Showing 5 changed files with 461 additions and 86 deletions.
1 change: 1 addition & 0 deletions changes/20250113134619.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:sparkles: [collections] Added Conditions type to provide a helper to deal with flags or boolean slices
216 changes: 216 additions & 0 deletions utils/collection/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package collection

import (
"fmt"

"github.com/ARM-software/golang-utils/utils/commonerrors"
)

type Conditions []bool

// NewConditions creates a set of conditions.
func NewConditions(capacity int) Conditions {
return make([]bool, 0, capacity)
}

// NewConditionsFromValues creates a set of conditions.
func NewConditionsFromValues(conditions ...bool) Conditions {
c := NewConditions(len(conditions))
c.Add(conditions...)
return c
}

// Add adds conditions and returns itself.
func (c *Conditions) Add(conditions ...bool) Conditions {
if c == nil {
return nil
}
*c = append(*c, conditions...)
return *c
}

// ForEach will execute function each() on every condition unless an error is returned and will end add this point.
func (c *Conditions) ForEach(each func(bool) error) error {
if c == nil || len(*c) == 0 {
return fmt.Errorf("%w: the collection of conditions is empty", commonerrors.ErrUndefined)
}
for i := range *c {
subErr := each((*c)[i])
if subErr != nil {
return subErr
}
}
return nil
}

// Contains returns whether the conditions collection contains the value of a condition.
func (c *Conditions) Contains(condition bool) bool {
if c == nil {
return false
}
if condition {
return c.Any()
} else {
return !c.All()
}
}

// All returns true if all conditions are true.
func (c *Conditions) All() bool {
if c == nil {
return false
}
return All(*c)
}

// Any returns true if there is at least one condition which is true.
func (c *Conditions) Any() bool {
if c == nil {
return false
}
return Any(*c)
}

// Concat concatenates conditions and returns itself.
func (c *Conditions) Concat(more *Conditions) Conditions {
if more == nil {
return nil
}
return c.Add(*more...)
}

// Negate returns a new set of conditions with negated values.
func (c *Conditions) Negate() Conditions {
if c == nil {
return nil
}
negation := Conditions(Negate(*c...))
return negation
}

// And performs an `and` operation on all conditions
func (c *Conditions) And() bool {
if c == nil {
return false
}
return And(*c...)
}

// Or performs an `Or` operation on all conditions
func (c *Conditions) Or() bool {
if c == nil {
return false
}
return Or(*c...)
}

// Xor performs a `Xor` operation on all conditions
func (c *Conditions) Xor() bool {
if c == nil {
return false
}
return Xor(*c...)
}

// OneHot performs an `OnHot` operation on all conditions
func (c *Conditions) OneHot() bool {
if c == nil {
return false
}
return OneHot(*c...)
}

// Any returns true if there is at least one element of the slice which is true.
func Any(slice []bool) bool {
if len(slice) == 0 {
return false
}
for i := range slice {
if slice[i] {
return true
}
}
return false
}

// AnyTrue returns whether there is a value set to true
func AnyTrue(values ...bool) bool {
return Any(values)
}

// All returns true if all items of the slice are true.
func All(slice []bool) bool {
if len(slice) == 0 {
return false
}
for i := range slice {
if !slice[i] {
return false
}
}
return true
}

// AllTrue returns whether all values are true.
func AllTrue(values ...bool) bool {
return All(values)
}

// Negate returns the slice with contrary values.
func Negate(values ...bool) []bool {
if values == nil {
return nil
}
if len(values) == 0 {
return []bool{}
}
negatedValues := make([]bool, len(values))
for i := range values {
negatedValues[i] = !values[i]
}
return negatedValues
}

// And performs an 'and' operation on an array of booleans.
func And(values ...bool) bool {
return All(values)
}

// Or performs an 'or' operation on an array of booleans.
func Or(values ...bool) bool {
return Any(values)
}

// Xor performs a `xor` on an array of booleans. This behaves like an XOR gate; it returns true if the number of true values is odd, and false if the number of true values is zero or even.
func Xor(values ...bool) bool {
if len(values) == 0 {
return false
}
// false if the neutral element of the xor operator
result := false
for i := range values {
result = xor(result, values[i])
}
return result
}

// xor(true, true) = false
// xor(false, false) = false
// xor(true, false) = true
func xor(a, b bool) bool {
return a != b
}

// OneHot returns true if one, and only one, of the supplied values is true. See https://en.wikipedia.org/wiki/One-hot
func OneHot(values ...bool) bool {
if len(values) == 0 {
return false
}
count := 0
for i := range values {
if values[i] {
count++
}
}
return count == 1
}
Loading

0 comments on commit 6531ccd

Please sign in to comment.