Skip to content

Commit

Permalink
docs: improve the documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mdawar committed Aug 23, 2024
1 parent 6a19bc4 commit 2349276
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 65 deletions.
97 changes: 57 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,63 +14,80 @@ go get -u github.com/mdawar/xmap

## Usage

#### New Map

```go
package main
// Create a map with the default configuration.
m := xmap.New[string, int]()
// Stop the cleanup goroutine and clear the map.
defer m.Stop()
```

import (
"context"
"fmt"
"time"
#### Create

"github.com/mdawar/xmap"
)
```go
// Create new entries in the map.
m.Set("a", 1, time.Minute) // Key that expires in 1 minute.
m.Set("b", 2, 0) // Key that never expires (0 TTL).

func main() {
// Create a map with the default configuration.
m := xmap.New[string, int]()
defer m.Stop() // Stop the cleanup goroutine and clear the map.
// Replace a key.
m.Set("a", 3, time.Hour) // Replace key (New value and expiration time).
```

// Create new entries in the map.
m.Set("a", 1, time.Minute) // Key that expires in 1 minute.
m.Set("b", 2, 0) // Key that never expires (0 TTL).
#### Update

// Replace a key.
m.Set("a", 3, time.Hour) // Replace key (New value and expiration time).
```go
// Update the value without changing the expiration time.
// Reports whether the key was updated (Key exists).
ok := m.Update("b", 4)
```

// Update the value without changing the expiration time.
// Reports whether the key was updated (Key exists).
ok := m.Update("b", 4)
#### Get

// Get the value if the key exists and has not expired.
// The second return value reports whether the key exists.
value, ok := m.Get("a")
```go
// Get the value if the key exists and has not expired.
// The second return value reports whether the key exists.
value, ok := m.Get("a")

// Get the value with the expiration time.
// The third return value reports whether the key exists.
value, expiration, ok := m.GetWithExpiration("a")
// If the key never expires, it will have a zero expiration time value.
neverExpires := expiration.IsZero()
```

#### Delete

// Get the value with the expiration time.
// The third return value reports whether the key exists.
value, expiration, ok := m.GetWithExpiration("a")
// If the key never expires, it will have a zero expiration time value.
neverExpires := expiration.IsZero()
```go
// Delete a key from the map.
m.Delete("a")

// Length of the map.
total := m.Len()
// Delete all the keys from the map.
m.Clear()
```

// Delete a key from the map.
m.Delete("a")
#### Length

// Delete all the keys from the map.
m.Clear()
```go
total := m.Len()
```

// Expired keys are automatically removed at regular intervals.
// Additionally, the removal of expired keys can be manually triggered.
removed := m.RemoveExpired() // Returns the number of removed keys.
#### Iteration

// Iterate over the map entries.
for key, value := range m.All() {
fmt.Println("Key:", key, "-", "Value:", value)
}
```go
for key, value := range m.All() {
fmt.Println("Key:", key, "-", "Value:", value)
}
```

#### Remove Expired Keys

```go
// Expired keys are automatically removed at regular intervals.
// Additionally, the removal of expired keys can be manually triggered.
removed := m.RemoveExpired() // Returns the number of removed keys.
```

## Configuration

| Name | Type | Description |
Expand Down
50 changes: 25 additions & 25 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import (
"time"
)

// entry is the value stored internally in the map.
// entry is the value stored internally in the [Map].
type entry[V any] struct {
value V // The actual value stored.
exp time.Time // The expiration time.
exp time.Time // The expiration time of the value.
}

// Config represents the Map configuration.
// Config represents the [Map] configuration.
type Config struct {
// CleanupInterval is the interval at which the expired keys are removed.
// Default: 5 minutes.
Expand All @@ -29,7 +29,7 @@ type Config struct {
TimeSource Time
}

// setDefaults sets the default values for the Map configuration.
// setDefaults sets the default values for the [Map] configuration.
func (c *Config) setDefaults() {
if c.CleanupInterval == 0 {
c.CleanupInterval = 5 * time.Minute
Expand All @@ -51,12 +51,12 @@ type Map[K comparable, V any] struct {
stopped atomic.Int32 // Map stopped flag.
}

// New creates a new Map instance with the default configuration.
// New creates a new [Map] instance with the default configuration.
func New[K comparable, V any]() *Map[K, V] {
return NewWithConfig[K, V](Config{})
}

// NewWithConfig creates a new Map instance with the specified configuration.
// NewWithConfig creates a new [Map] instance with the specified configuration.
func NewWithConfig[K comparable, V any](cfg Config) *Map[K, V] {
cfg.setDefaults()

Expand All @@ -72,12 +72,12 @@ func NewWithConfig[K comparable, V any](cfg Config) *Map[K, V] {
return m
}

// Stop halts the background cleanup goroutine and clears the map.
// It should be called when the map is no longer needed.
// Stop halts the background cleanup goroutine and clears the [Map].
// It should be called when the [Map] is no longer needed.
//
// This method is safe to be called multiple times.
//
// A stopped map should not be re-used, a new map should be created instead.
// A stopped [Map] should not be re-used, a new [Map] should be created instead.
func (m *Map[K, V]) Stop() {
if m.stopped.CompareAndSwap(0, 1) {
// Stop the cleanup goroutine.
Expand All @@ -90,27 +90,27 @@ func (m *Map[K, V]) Stop() {
}
}

// Stopped reports whether the Map is stopped.
// Stopped reports whether the [Map] is stopped.
//
// Expired keys are not removed automatically in a stopped map.
// Expired keys are not removed automatically in a stopped [Map].
func (m *Map[K, V]) Stopped() bool {
return m.stopped.Load() == 1
}

// Len returns the length of the map.
// Len returns the length of the [Map].
//
// The length of the map is the total number of keys, including the expired
// The length of the [Map] is the total number of keys, including the expired
// keys that have not been removed yet.
//
// To get the length excluding the number of expired keys, call RemoveExpired
// To get the length excluding the number of expired keys, call [Map.RemoveExpired]
// before calling this method.
func (m *Map[K, V]) Len() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.kv)
}

// Set creates or replaces a key/value pair in the map.
// Set creates or replaces a key-value pair in the [Map].
//
// A key can be set to never expire with a ttl value of 0.
func (m *Map[K, V]) Set(key K, value V, ttl time.Duration) {
Expand Down Expand Up @@ -141,7 +141,7 @@ func (m *Map[K, V]) Update(key K, value V) bool {

// Get returns the value associated with the key.
//
// The second bool return value reports whether the key exists in the map.
// The second bool return value reports whether the key exists in the [Map].
func (m *Map[K, V]) Get(key K) (V, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
Expand All @@ -156,7 +156,7 @@ func (m *Map[K, V]) Get(key K) (V, bool) {

// GetWithExpiration returns the value and expiration time of the key.
//
// The third bool return value reports whether the key exists in the map.
// The third bool return value reports whether the key exists in the [Map].
func (m *Map[K, V]) GetWithExpiration(key K) (V, time.Time, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
Expand All @@ -169,7 +169,7 @@ func (m *Map[K, V]) GetWithExpiration(key K) (V, time.Time, bool) {
return zero, time.Time{}, false
}

// All returns an iterator over key-value pairs from the Map.
// All returns an iterator over key-value pairs from the [Map].
//
// Only the entries that have not expired are produced during the iteration.
//
Expand All @@ -189,23 +189,23 @@ func (m *Map[K, V]) All() iter.Seq2[K, V] {
}
}

// Delete removes a key from the map.
// Delete removes a key from the [Map].
func (m *Map[K, V]) Delete(key K) {
m.mu.Lock()
delete(m.kv, key)
m.mu.Unlock()
}

// Clear removes all the entries from the map.
// Clear removes all the entries from the [Map].
func (m *Map[K, V]) Clear() {
m.mu.Lock()
clear(m.kv)
m.mu.Unlock()
}

// cleanup removes expired keys from the map in an interval.
// cleanup removes expired keys from the [Map] in an interval.
//
// The cleanup is stopped by calling Stop.
// The cleanup is stopped by calling [Map.Stop].
func (m *Map[K, V]) cleanup() {
ticker := m.time.NewTicker(m.interval)
defer ticker.Stop()
Expand All @@ -229,9 +229,9 @@ func (m *Map[K, V]) CleanupActive() bool {
return m.active.Load() == 1
}

// RemoveExpired checks the map keys and removes the expired ones.
// RemoveExpired checks the [Map] keys and removes the expired ones.
//
// It returns the number of keys that have expired.
// It returns the number of keys that were removed.
func (m *Map[K, V]) RemoveExpired() int {
// Expired keys.
var expired []K
Expand All @@ -255,7 +255,7 @@ func (m *Map[K, V]) RemoveExpired() int {
return len(expired)
}

// expired reports whether an entry has expired.
// expired reports whether an [entry] has expired.
func (m *Map[K, V]) expired(entry *entry[V]) bool {
return !entry.exp.IsZero() && m.time.Now().After(entry.exp)
}

0 comments on commit 2349276

Please sign in to comment.