Skip to content

Commit

Permalink
Rather than having a Params interfaced exposed directly, it is now a …
Browse files Browse the repository at this point in the history
…Params

struct which internally uses the interface. This extra layer of indirection
allows for a cleaner consumer API. Specifically, it is no longer necessary (or
even supported) to continously re-assign Set to itself.
  • Loading branch information
karlseguin committed Mar 22, 2015
1 parent 8b0b67c commit 20ed02d
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 88 deletions.
37 changes: 6 additions & 31 deletions arrayparams.go
Expand Up @@ -4,23 +4,10 @@ package params
// More memory efficient and faster for a small number of keys (~10)
// Also, can be pooled and reused
type ArrayParams struct {
pool *Pool
length int
lookup []struct{ key, value string }
}

// Create a new ArrayParam that can hold up to length pairs
func New(length int) Params {
return pooled(nil, length)
}

func pooled(pool *Pool, length int) Params {
return &ArrayParams{
pool: pool,
lookup: make([]struct{ key, value string }, length),
}
}

// Get a value by key
func (p *ArrayParams) Get(key string) (string, bool) {
position, exists := p.indexOf(key)
Expand All @@ -33,17 +20,15 @@ func (p *ArrayParams) Get(key string) (string, bool) {
// Set the value to the specified key
// Set can return a new Params object better equipped to handle the large size
// (always assign the result of Set back to the params variable, like you do with append)
func (p *ArrayParams) Set(key, value string) Params {
func (p *ArrayParams) Set(key, value string) bool {
position, exists := p.indexOf(key)
if exists {
p.lookup[position].value = value
return p
return true
}

if p.length == len(p.lookup) {
m := p.toMap(key, value)
p.Release()
return m
return false
}

pair := struct{ key, value string }{key, value}
Expand All @@ -54,7 +39,7 @@ func (p *ArrayParams) Set(key, value string) Params {
p.lookup[position] = pair
}
p.length += 1
return p
return true
}

// Iterate over each key value pair
Expand All @@ -71,9 +56,8 @@ func (p *ArrayParams) Len() int {
}

// Clears the param
func (p *ArrayParams) Clear() Params {
func (p *ArrayParams) Clear() {
p.length = 0
return p
}

// Delete a value by key
Expand All @@ -90,7 +74,7 @@ func (p *ArrayParams) Delete(key string) (string, bool) {
return value, true
}

func (p *ArrayParams) toMap(key, value string) Params {
func (p *ArrayParams) ToMap(key, value string) params {
m := make(MapParams, p.length+1)
p.Each(func(key, value string) { m[key] = value })
m[key] = value
Expand All @@ -109,12 +93,3 @@ func (p *ArrayParams) indexOf(key string) (int, bool) {
}
return p.length, false
}

// Return the params to the pool
// Safe to call on non-pooled params
func (p *ArrayParams) Release() {
if p.pool != nil {
p.length = 0
p.pool.list <- p
}
}
6 changes: 2 additions & 4 deletions empty.go
Expand Up @@ -8,8 +8,7 @@ func (p EmptyParams) Get(key string) (string, bool) {
return "", false
}

func (p EmptyParams) Set(key, value string) Params {
return p
func (p EmptyParams) Set(key, value string) {
}

func (p EmptyParams) Each(f func(string, value string)) {
Expand All @@ -26,6 +25,5 @@ func (p EmptyParams) Delete(key string) (string, bool) {
return "", false
}

func (p EmptyParams) Clear() Params {
return p
func (p EmptyParams) Clear() {
}
15 changes: 7 additions & 8 deletions mapparams.go
Expand Up @@ -7,9 +7,9 @@ func (p MapParams) Get(key string) (string, bool) {
return v, k
}

func (p MapParams) Set(key, value string) Params {
func (p MapParams) Set(key, value string) bool {
p[key] = value
return p
return true
}

func (p MapParams) Delete(key string) (string, bool) {
Expand All @@ -26,14 +26,13 @@ func (p MapParams) Each(f func(string, value string)) {
}
}

func (p MapParams) Release() {

}

func (p MapParams) Len() int {
return len(p)
}

func (p MapParams) Clear() Params {
return make(MapParams)
func (p MapParams) Clear() {
}

func (p MapParams) ToMap(key, value string) params {
return p
}
62 changes: 58 additions & 4 deletions params.go
Expand Up @@ -2,12 +2,66 @@
package params

// An interface to a key-value lookup
type Params interface {
type params interface {
Get(key string) (string, bool)
Set(key, value string) Params
Set(key, value string) bool
ToMap(key, value string) params
Delete(key string) (string, bool)
Release()
Each(func(key, value string))
Len() int
Clear() Params
Clear()
}

type Params struct {
pool *Pool
fast params
current params
}

// Creates a new params object
func New(length int) *Params {
return pooled(nil, length)
}

func pooled(pool *Pool, length int) *Params {
ap := &ArrayParams{
lookup: make([]struct{ key, value string }, length),
}
return &Params{
pool: pool,
fast: ap,
current: ap,
}
}

func (p *Params) Get(key string) (string, bool) {
return p.current.Get(key)
}

func (p *Params) Set(key, value string) {
if p.current.Set(key, value) == false {
p.current = p.current.ToMap(key, value)
}
}
func (p *Params) Delete(key string) (string, bool) {
return p.current.Delete(key)
}

func (p *Params) Each(f func(key, value string)) {
p.current.Each(f)
}

func (p *Params) Len() int {
return p.current.Len()
}

func (p *Params) Clear() {
p.current = p.fast
p.current.Clear()
}

func (p *Params) Release() {
if p.pool != nil {
p.Clear()
}
}
40 changes: 15 additions & 25 deletions arrayparams_test.go → params_test.go
Expand Up @@ -17,9 +17,9 @@ func (_ ArrayParamsTests) GetsFromEmpty() {

func (_ ArrayParamsTests) GetsAValue() {
p := New(10)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p = p.Set("duncan", "")
p.Set("leto", "ghanima")
p.Set("paul", "alia")
p.Set("duncan", "")
Expect(p.Get("leto")).To.Equal("ghanima", true)
Expect(p.Get("paul")).To.Equal("alia", true)
Expect(p.Get("duncan")).To.Equal("", true)
Expand All @@ -28,36 +28,26 @@ func (_ ArrayParamsTests) GetsAValue() {

func (_ ArrayParamsTests) OverwritesAnExistingValue() {
p := New(10)
p = p.Set("leto", "ghaima")
p = p.Set("leto", "ghanima")
p.Set("leto", "ghaima")
p.Set("leto", "ghanima")
Expect(p.Get("leto")).To.Equal("ghanima", true)
}

func (_ ArrayParamsTests) ExpandsBeyondTheSpecifiedSize() {
p := New(1)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p.Set("leto", "ghanima")
p.Set("paul", "alia")
Expect(p.Get("leto")).To.Equal("ghanima", true)
Expect(p.Get("paul")).To.Equal("alia", true)
Expect(p.Get("vladimir")).To.Equal("", false)
_, ok := p.(MapParams)
_, ok := p.current.(MapParams)
Expect(ok).ToEqual(true)
}

func (_ ArrayParamsTests) ExpansionReleasesTheParam() {
pool := NewPool(1, 1)
p := pool.Checkout()
Expect(len(pool.list)).To.Equal(0)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
Expect(len(pool.list)).To.Equal(1)
Expect(pool.Checkout().(*ArrayParams).length).ToEqual(0)
}

func (_ ArrayParamsTests) Iterates() {
p := New(10)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p.Set("leto", "ghanima")
p.Set("paul", "alia")
saw := make(map[string]string, 2)
p.Each(func(key, value string) {
saw[key] = value
Expand All @@ -69,8 +59,8 @@ func (_ ArrayParamsTests) Iterates() {

func (_ ArrayParamsTests) ClearsTheParam() {
p := New(10)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p.Set("leto", "ghanima")
p.Set("paul", "alia")
p.Clear()
Expect(p.Len()).To.Equal(0)
Expect(p.Get("leto")).To.Equal("", false)
Expand All @@ -96,9 +86,9 @@ func (_ ArrayParamsTests) DeletesOneItem() {

func (_ ArrayParamsTests) DeletesAnItem() {
p := New(10)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p = p.Set("duncan", "")
p.Set("leto", "ghanima")
p.Set("paul", "alia")
p.Set("duncan", "")
Expect(p.Delete("leto")).To.Equal("ghanima", true)
Expect(p.Len()).To.Equal(2)
Expect(p.Get("duncan")).To.Equal("", true)
Expand Down
6 changes: 3 additions & 3 deletions pool.go
Expand Up @@ -8,7 +8,7 @@ import (
type Pool struct {
misses int64
size int
list chan Params
list chan *Params
}

// Create a new pool of count params.
Expand All @@ -17,7 +17,7 @@ type Pool struct {
func NewPool(size, count int) *Pool {
pool := &Pool{
size: size,
list: make(chan Params, count),
list: make(chan *Params, count),
}
for i := 0; i < count; i++ {
pool.list <- pooled(pool, size)
Expand All @@ -32,7 +32,7 @@ func (p *Pool) Misses() int64 {
}

// Get a param from the pool or create a new one if the pool is empty
func (p *Pool) Checkout() Params {
func (p *Pool) Checkout() *Params {
select {
case item := <-p.list:
return item
Expand Down
16 changes: 3 additions & 13 deletions readme.md
Expand Up @@ -15,20 +15,10 @@ The approach is discussed [here](http://openmymind.net/Using-Small-Arrays-Instea
```go
// create a params object that can hold 3 pairs
p := New(3)
p = p.Set("leto", "ghanima")
p.Set("leto", "ghanima")
fmt.Println(p.Get("leto"))
```

**It's important to note that when you put more than the configured number of pairs, the object will convert itself to a `map[string]string`.** Therefore, you must re-assign the return value of `Set`, much like you do with Go's built-in `append`:

```go
p := New(2)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p = p.Set("feyd", "glossu")
//p is now a different type of object
```

## Delete
An item can be deleted from the set using `Delete(key string)`. The returned values are the same as `Get`, that is, the value and a boolean indicating if the value existing.

Expand All @@ -37,8 +27,8 @@ Use the `Each(func(key, value string))` function to iterate through the params:

```go
p := New(2)
p = p.Set("leto", "ghanima")
p = p.Set("paul", "alia")
p.Set("leto", "ghanima")
p.Set("paul", "alia")
p.Each(func(key, value string){
fmt.Println("%s = %s", key, value)
})
Expand Down

0 comments on commit 20ed02d

Please sign in to comment.