> ## Documentation Index
> Fetch the complete documentation index at: https://osinet.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Set

> Generic set with union, intersection, and difference operations.

`Set` is a generic collection that holds at most one copy of each element. It
provides membership tests, iteration, and the classic set algebra operations:
union, intersection, and difference.

## Installation

```go theme={null}
import "github.com/fgm/container/set"
```

## Constructor

```go theme={null}
func NewBasicMap[E comparable](sizeHint int) container.Set[E]
```

<ParamField path="sizeHint" type="int" required>
  A hint for the initial capacity of the internal map. Pass `0` if you have no
  estimate. This does not impose a maximum size.
</ParamField>

```go theme={null}
s := set.NewBasicMap[string](64)
```

The element type `E` must satisfy the `comparable` constraint so it can be used
as a map key.

## Methods

### Membership

| Method     | Signature                     | Description                                                                                                |
| ---------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `Add`      | `Add(item E) (found bool)`    | Adds `item` to the set. Returns `true` if the item was **already present** before this call.               |
| `Remove`   | `Remove(item E) (found bool)` | Removes `item` from the set. Returns `true` if the item **was present**. Safe to call with a missing item. |
| `Contains` | `Contains(item E) bool`       | Returns `true` if `item` is in the set.                                                                    |
| `Clear`    | `Clear() (count int)`         | Removes all elements and returns how many were removed.                                                    |
| `Items`    | `Items() iter.Seq[E]`         | Returns an iterator over all elements (unordered).                                                         |

<Note>
  `Add` returns `true` when the item was **already** in the set, not when it
  was newly added. This mirrors a "was it found?" semantic consistent with the
  rest of the library. Check `!found` if you want to know whether insertion was
  new.
</Note>

### Set operations

| Method         | Signature                           | Description                                                                        |
| -------------- | ----------------------------------- | ---------------------------------------------------------------------------------- |
| `Union`        | `Union(other Set[E]) Set[E]`        | Returns a new set containing every element from either set.                        |
| `Intersection` | `Intersection(other Set[E]) Set[E]` | Returns a new set containing only elements present in both sets.                   |
| `Difference`   | `Difference(other Set[E]) Set[E]`   | Returns a new set containing elements in the receiver that are **not** in `other`. |

<Tip>
  For degenerate cases (nil or empty sets), `Union`, `Intersection`, and
  `Difference` may return the receiver or the argument directly without
  allocating a new set. Do not mutate the result if you still need the original
  sets to be unchanged.
</Tip>

## Optional `Countable` interface

`BasicMap` also satisfies `container.Countable`, which adds a `Len()` method.
Guard the call with a type assertion for forward compatibility:

```go theme={null}
if c, ok := s.(container.Countable); ok {
    fmt.Printf("elements in set: %d\n", c.Len())
}
```

## Example

```go theme={null}
package main

import (
    "fmt"

    "github.com/fgm/container"
    "github.com/fgm/container/set"
)

func main() {
    evens := set.NewBasicMap[int](8)
    odds := set.NewBasicMap[int](8)

    for i := 0; i < 10; i++ {
        if i%2 == 0 {
            evens.Add(i)
        } else {
            odds.Add(i)
        }
    }

    // Check the length via the optional Countable interface.
    if c, ok := evens.(container.Countable); ok {
        fmt.Printf("even count: %d\n", c.Len())
    }

    // Contains
    fmt.Println("contains 4:", evens.Contains(4))
    fmt.Println("contains 5:", evens.Contains(5))

    // Add returns true if the item was already present.
    wasPresent := evens.Add(4)
    fmt.Println("4 was already present:", wasPresent)

    // Remove returns true if the item was present.
    wasPresent = evens.Remove(4)
    fmt.Println("4 removed (was present):", wasPresent)
    wasPresent = evens.Remove(4)
    fmt.Println("4 removed again (was present):", wasPresent)

    // Set operations.
    primes := set.NewBasicMap[int](4)
    for _, p := range []int{2, 3, 5, 7} {
        primes.Add(p)
    }

    evenPrimes := evens.Intersection(primes)
    fmt.Print("even primes: ")
    for item := range evenPrimes.Items() {
        fmt.Print(item, " ")
    }
    fmt.Println()

    allNumbers := evens.Union(odds)
    if c, ok := allNumbers.(container.Countable); ok {
        fmt.Printf("union size: %d\n", c.Len())
    }

    notPrime := evens.Difference(primes)
    fmt.Print("even non-primes: ")
    for item := range notPrime.Items() {
        fmt.Print(item, " ")
    }
    fmt.Println()
}
```

## Iterating with Items

`Items()` returns an `iter.Seq[E]` compatible with Go 1.23+ range-over-func:

```go theme={null}
for item := range s.Items() {
    fmt.Println(item)
}
```

The iteration order is not guaranteed. If you need a sorted view, collect into
a slice and sort it:

```go theme={null}
var slice []string
for item := range s.Items() {
    slice = append(slice, item)
}
slices.Sort(slice)
```

<Note>
  `Set` is not concurrency-safe. If multiple goroutines need to read or modify
  the same set concurrently, add external synchronization (for example, a
  `sync.RWMutex`).
</Note>
