gcache icon indicating copy to clipboard operation
gcache copied to clipboard

Increment operator

Open jadbox opened this issue 8 years ago • 7 comments

It would be great that instead of a Get+Set that there was an Increment operator, ideally goroutine safe.

jadbox avatar Jun 27 '16 03:06 jadbox

Sorry for late reply. Thanks your advice. I'm planning to implement GetAndSet method which enables a such operation.

bluele avatar Jul 14 '16 07:07 bluele

@bluele If you detail the spec you have in mind for that method, I'll be happy to implement it.

erwanor avatar May 25 '17 04:05 erwanor

Thanks, @aaronwinter . Hmm... How about with the following design?

func (c *LRUCache) GetOrSet(key, value interface{}) (interface{}, error) {
	v, err := c.get(key, false)
	if err == KeyNotFoundError {
        it, err := c.set(key, value)
        return it.value, err
	}
	return v, err
}

Or is it better to give a function that returns a value rather than a value?

bluele avatar May 25 '17 15:05 bluele

This seems potentially problematic to design because of the problem of dealing with interface{} and then having to interpret those values as one of the numeric values. You could potentially have two Increment methods, one for integers and one for floats that attempts to enforce int64 and float64 respectively.

pcman312 avatar Jun 08 '17 19:06 pcman312

https://github.com/patrickmn/go-cache/blob/master/cache.go#L182

// Increment an item of type int, int8, int16, int32, int64, uintptr, uint,
// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
// item's value is not an integer, if it was not found, or if it is not
// possible to increment it by n. To retrieve the incremented value, use one
// of the specialized methods, e.g. IncrementInt64.
func (c *cache) Increment(k string, n int64) error {
	c.mu.Lock()
	v, found := c.items[k]
	if !found || v.Expired() {
		c.mu.Unlock()
		return fmt.Errorf("Item %s not found", k)
	}
	switch v.Object.(type) {
	case int:
		v.Object = v.Object.(int) + int(n)
	case int8:
		v.Object = v.Object.(int8) + int8(n)
	case int16:
		v.Object = v.Object.(int16) + int16(n)
	case int32:
		v.Object = v.Object.(int32) + int32(n)
	case int64:
		v.Object = v.Object.(int64) + n
	case uint:
		v.Object = v.Object.(uint) + uint(n)
	case uintptr:
		v.Object = v.Object.(uintptr) + uintptr(n)
	case uint8:
		v.Object = v.Object.(uint8) + uint8(n)
	case uint16:
		v.Object = v.Object.(uint16) + uint16(n)
	case uint32:
		v.Object = v.Object.(uint32) + uint32(n)
	case uint64:
		v.Object = v.Object.(uint64) + uint64(n)
	case float32:
		v.Object = v.Object.(float32) + float32(n)
	case float64:
		v.Object = v.Object.(float64) + float64(n)
	default:
		c.mu.Unlock()
		return fmt.Errorf("The value for %s is not an integer", k)
	}
	c.items[k] = v
	c.mu.Unlock()
	return nil
}

sergerdn avatar Jan 22 '21 21:01 sergerdn

@sergerdn I think that's the best solution here that you posted above (at least until Go gets generic typing support).

jadbox avatar Feb 01 '21 04:02 jadbox

@sergerdn I think that's the best solution here that you posted above (at least until Go gets generic typing support).

@jadbox Have a look another solution with code generators, it looks not bad too:

  • https://github.com/zgoat/zcache/blob/master/gen.go
  • https://github.com/zgoat/zcache/blob/master/incr.go

It supports decrement also.

sergerdn avatar Feb 01 '21 05:02 sergerdn