Решение на ExpireMap от Иван Боршуков

Обратно към всички решения

Към профила на Иван Боршуков

Резултати

  • 0 точки от тестове
  • 0 бонус точки
  • 0 точки общо
  • 0 успешни тест(а)
  • 25 неуспешни тест(а)

Код

package main
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
)
type ExpireMap struct {
m map[string]interface{}
expireTimes map[string]time.Time
mtx sync.Mutex
stop chan struct{}
expired chan string
expiredListeners []chan string
}
func NewExpireMap() (em *ExpireMap) {
em = &ExpireMap{}
em.m = make(map[string]interface{})
em.expireTimes = make(map[string]time.Time)
em.stop = make(chan struct{})
em.expired = make(chan string)
em.expiredListeners = make([]chan string, 0)
go em.cycle()
go em.sendExpired()
return
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.mtx.Lock()
em.expireTimes[key] = time.Now().Add(expire)
em.m[key] = value
em.mtx.Unlock()
}
func (em *ExpireMap) Get(key string) (value interface{}, found bool) {
value, found = em.m[key]
return
}
func (em *ExpireMap) Contains(key string) (found bool) {
_, found = em.m[key]
return
}
func (em *ExpireMap) Delete(key string) {
if _, found := em.m[key]; !found {
panic("Whoa! There is not such key to delete.")
}
em.mtx.Lock()
delete(em.expireTimes, key)
delete(em.m, key)
em.mtx.Unlock()
}
func (em *ExpireMap) Size() int {
return len(em.m)
}
func (em *ExpireMap) Expires(key string) (expires time.Time, found bool) {
expires, found = em.expireTimes[key]
return
}
func (em *ExpireMap) Cleanup() {
em.mtx.Lock()
em.expireTimes = make(map[string]time.Time)
em.m = make(map[string]interface{})
em.mtx.Unlock()
}
func (em *ExpireMap) Destroy() {
em.mtx.Lock()
em.expireTimes = nil
em.m = nil
em.stop <- struct{}{}
em.stop <- struct{}{}
em.mtx.Unlock()
}
func (em *ExpireMap) ExpiredChan() <-chan string {
em.mtx.Lock()
c := make(chan string)
em.expiredListeners = append(em.expiredListeners, c)
em.mtx.Unlock()
return c
}
func (em *ExpireMap) GetInt(key string) (intValue int, ok bool) {
value, found := em.m[key]
if !found {
return
}
intValue, ok = value.(int)
return
}
func (em *ExpireMap) GetFloat64(key string) (floatValue float64, ok bool) {
value, found := em.m[key]
if !found {
return
}
floatValue, ok = value.(float64)
return
}
func (em *ExpireMap) GetBool(key string) (boolValue bool, ok bool) {
value, found := em.m[key]
if !found {
return
}
boolValue, ok = value.(bool)
return
}
func (em *ExpireMap) GetString(key string) (stringValue string, ok bool) {
value, found := em.m[key]
if !found {
return
}
stringValue, ok = value.(string)
return
}
func (em *ExpireMap) ToUpper(key string) error {
defer em.mtx.Unlock()
em.mtx.Lock()
stringValue, found := em.GetString(key)
if !found {
return errors.New(fmt.Sprintf("There is no value for key %s.", key))
}
em.m[key] = strings.ToUpper(stringValue)
return nil
}
func (em *ExpireMap) Increment(key string) error {
return em.add(key, 1)
}
func (em *ExpireMap) Decrement(key string) error {
return em.add(key, -1)
}
func (em *ExpireMap) cycle() {
for {
select {
case <-em.stop:
return
default:
for key, expireTime := range em.expireTimes {
if !(time.Now().Before(expireTime)) {
em.mtx.Lock()
delete(em.expireTimes, key)
delete(em.m, key)
em.mtx.Unlock()
go func(key string) {
em.expired <- key
}(key)
}
}
}
}
}
func (em *ExpireMap) sendExpired() {
for {
select {
case expired := <-em.expired:
for _, c := range em.expiredListeners {
go func(c chan string) {
c <- expired
}(c)
}
case <-em.stop:
for _, c := range em.expiredListeners {
close(c)
}
return
}
}
}
func (em *ExpireMap) add(key string, toAdd int) error {
defer em.mtx.Unlock()
em.mtx.Lock()
intValue, found := em.GetInt(key)
if found {
em.m[key] = intValue + toAdd
return nil
}
stringValue, found := em.GetString(key)
if found {
intValue, err := strconv.Atoi(stringValue)
if err != nil {
return err
}
em.m[key] = strconv.Itoa(intValue + toAdd)
return nil
}
return errors.New(fmt.Sprintf("There is no value for key %s.", key))
}

Лог от изпълнението

# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]
# _/tmp/d20141204-6466-1hb55ag
./solution_test.go:928: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
./solution_test.go:951: em.ToLower undefined (type *ExpireMap has no field or method ToLower)
FAIL	_/tmp/d20141204-6466-1hb55ag [build failed]

История (2 версии и 2 коментара)

Иван обнови решението на 17.11.2014 19:04 (преди над 3 години)

+package main
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+type timestampMap struct {
+ mtx sync.Mutex // use RWMutex instead?
+ Values map[string]time.Time
+}
+
+func (tm *timestampMap) Set(key string, t time.Time) {
+ tm.mtx.Lock()
+ tm.Values[key] = t
+ tm.mtx.Unlock()
+}
+
+func (tm *timestampMap) Unset(key string) {
+ tm.mtx.Lock()
+ delete(tm.Values, key)
+ tm.mtx.Unlock()
+}
+
+func (tm *timestampMap) Clear() {
+ tm.mtx.Lock()
+ tm.Values = make(map[string]time.Time)
+ tm.mtx.Unlock()
+}
+
+type ExpireMap struct {
+ m map[string]interface{}
+ expireTimes *timestampMap
+ stop chan struct{}
+ expired chan string
+}
+
+func NewExpireMap() (em *ExpireMap) {
+ em = &ExpireMap{}
+ em.m = make(map[string]interface{})
+
+ expireTimes := &timestampMap{}
+ expireTimes.Values = make(map[string]time.Time)
+ em.expireTimes = expireTimes
+
+ em.stop = make(chan struct{})
+ em.expired = make(chan string)
+
+ go em.cycle()
+
+ return
+}
+
+func (em *ExpireMap) cycle() {
+ for {
+ select {
+ case <-em.stop:
+ return
+ default:
+ for key, expireTime := range em.expireTimes.Values {
+ if !time.Now().Before(expireTime) {
+ em.expireTimes.Unset(key)
+ delete(em.m, key)
+ go func(key string) {
+ em.expired <- key
+ }(key)
+ }
+ }
+ }
+ }
+}
+
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.expireTimes.Set(key, time.Now().Add(expire))
+ em.m[key] = value
+}
+
+func (em *ExpireMap) Get(key string) (value interface{}, found bool) {
+ value, found = em.m[key]
+ return
+}
+
+func (em *ExpireMap) Contains(key string) (found bool) {
+ _, found = em.m[key]
+ return
+}
+
+func (em *ExpireMap) Delete(key string) {
+ if _, found := em.m[key]; !found {
+ panic("Whoa! There is not such key to delete.")
+ }
+ em.expireTimes.Unset(key)
+ delete(em.m, key)
+}
+
+func (em *ExpireMap) Size() int {
+ return len(em.m)
+}
+
+func (em *ExpireMap) Expires(key string) (expires time.Time, found bool) {
+ expires, found = em.expireTimes.Values[key]
+ return
+}
+
+func (em *ExpireMap) Cleanup() {
+ em.expireTimes.Clear()
+ em.m = make(map[string]interface{})
+}
+
+func (em *ExpireMap) Destroy() {
+ em.stop <- struct{}{}
+ em.expireTimes = nil
+ em.m = nil
+}
+
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.expired
+}
+
+func (em *ExpireMap) GetInt(key string) (intValue int, ok bool) {
+ value, found := em.m[key]
+ if !found {
+ return
+ }
+ intValue, ok = value.(int)
+ return
+}
+
+func (em *ExpireMap) GetFloat64(key string) (floatValue float64, ok bool) {
+ value, found := em.m[key]
+ if !found {
+ return
+ }
+ floatValue, ok = value.(float64)
+ return
+}
+
+func (em *ExpireMap) GetBool(key string) (boolValue bool, ok bool) {
+ value, found := em.m[key]
+ if !found {
+ return
+ }
+ boolValue, ok = value.(bool)
+ return
+}
+
+func (em *ExpireMap) GetString(key string) (stringValue string, ok bool) {
+ value, found := em.m[key]
+ if !found {
+ return
+ }
+ stringValue, ok = value.(string)
+ return
+}
+
+func (em *ExpireMap) ToUpper(key string) error {
+ stringValue, found := em.GetString(key)
+ if !found {
+ return errors.New(fmt.Sprintf("There is no value for key %s.", key))
+ }
+ em.m[key] = strings.ToUpper(stringValue)
+ return nil
+}
+
+func (em *ExpireMap) Increment(key string) error {
+ return em.add(key, 1)
+}
+
+func (em *ExpireMap) Decrement(key string) error {
+ return em.add(key, -1)
+}
+
+func (em *ExpireMap) add(key string, toAdd int) error {
+ intValue, found := em.GetInt(key)
+ if found {
+ em.m[key] = intValue + toAdd
+ return nil
+ }
+ stringValue, found := em.GetString(key)
+ if found {
+ intValue, err := strconv.Atoi(stringValue)
+ if err != nil {
+ return err
+ }
+ em.m[key] = strconv.Itoa(intValue + toAdd)
+ return nil
+ }
+ return errors.New(fmt.Sprintf("There is no value for key %s.", key))
+}

Иван обнови решението на 17.11.2014 22:56 (преди над 3 години)

package main
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
)
-type timestampMap struct {
- mtx sync.Mutex // use RWMutex instead?
- Values map[string]time.Time
-}
-
-func (tm *timestampMap) Set(key string, t time.Time) {
- tm.mtx.Lock()
- tm.Values[key] = t
- tm.mtx.Unlock()
-}
-
-func (tm *timestampMap) Unset(key string) {
- tm.mtx.Lock()
- delete(tm.Values, key)
- tm.mtx.Unlock()
-}
-
-func (tm *timestampMap) Clear() {
- tm.mtx.Lock()
- tm.Values = make(map[string]time.Time)
- tm.mtx.Unlock()
-}
-
type ExpireMap struct {
- m map[string]interface{}
- expireTimes *timestampMap
- stop chan struct{}
- expired chan string
+ m map[string]interface{}
+ expireTimes map[string]time.Time
+ mtx sync.Mutex
+ stop chan struct{}
+ expired chan string
+ expiredListeners []chan string
}
func NewExpireMap() (em *ExpireMap) {
em = &ExpireMap{}
em.m = make(map[string]interface{})
- expireTimes := &timestampMap{}
- expireTimes.Values = make(map[string]time.Time)
- em.expireTimes = expireTimes
+ em.expireTimes = make(map[string]time.Time)
em.stop = make(chan struct{})
em.expired = make(chan string)
+ em.expiredListeners = make([]chan string, 0)
go em.cycle()
+ go em.sendExpired()
return
}
-func (em *ExpireMap) cycle() {
- for {
- select {
- case <-em.stop:
- return
- default:
- for key, expireTime := range em.expireTimes.Values {
- if !time.Now().Before(expireTime) {
- em.expireTimes.Unset(key)
- delete(em.m, key)
- go func(key string) {
- em.expired <- key
- }(key)
- }
- }
- }
- }
-}
-
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
- em.expireTimes.Set(key, time.Now().Add(expire))
+ em.mtx.Lock()
+ em.expireTimes[key] = time.Now().Add(expire)
em.m[key] = value
+ em.mtx.Unlock()
}
func (em *ExpireMap) Get(key string) (value interface{}, found bool) {
value, found = em.m[key]
return
}
func (em *ExpireMap) Contains(key string) (found bool) {
_, found = em.m[key]
return
}
func (em *ExpireMap) Delete(key string) {
if _, found := em.m[key]; !found {
panic("Whoa! There is not such key to delete.")
}
- em.expireTimes.Unset(key)
+ em.mtx.Lock()
+ delete(em.expireTimes, key)
delete(em.m, key)
+ em.mtx.Unlock()
}
func (em *ExpireMap) Size() int {
return len(em.m)
}
func (em *ExpireMap) Expires(key string) (expires time.Time, found bool) {
- expires, found = em.expireTimes.Values[key]
+ expires, found = em.expireTimes[key]
return
}
func (em *ExpireMap) Cleanup() {
- em.expireTimes.Clear()
+ em.mtx.Lock()
+ em.expireTimes = make(map[string]time.Time)
em.m = make(map[string]interface{})
+ em.mtx.Unlock()
}
func (em *ExpireMap) Destroy() {
- em.stop <- struct{}{}
+ em.mtx.Lock()
em.expireTimes = nil
em.m = nil
+ em.stop <- struct{}{}
+ em.stop <- struct{}{}
+ em.mtx.Unlock()
}
func (em *ExpireMap) ExpiredChan() <-chan string {
- return em.expired
+ em.mtx.Lock()
+ c := make(chan string)
+ em.expiredListeners = append(em.expiredListeners, c)
+ em.mtx.Unlock()
+ return c
}
func (em *ExpireMap) GetInt(key string) (intValue int, ok bool) {
value, found := em.m[key]
if !found {
return
}
intValue, ok = value.(int)
return
}
func (em *ExpireMap) GetFloat64(key string) (floatValue float64, ok bool) {
value, found := em.m[key]
if !found {
return
}
floatValue, ok = value.(float64)
return
}
func (em *ExpireMap) GetBool(key string) (boolValue bool, ok bool) {
value, found := em.m[key]
if !found {
return
}
boolValue, ok = value.(bool)
return
}
func (em *ExpireMap) GetString(key string) (stringValue string, ok bool) {
value, found := em.m[key]
if !found {
return
}
stringValue, ok = value.(string)
return
}
func (em *ExpireMap) ToUpper(key string) error {
+ defer em.mtx.Unlock()
+ em.mtx.Lock()
stringValue, found := em.GetString(key)
if !found {
return errors.New(fmt.Sprintf("There is no value for key %s.", key))
}
em.m[key] = strings.ToUpper(stringValue)
return nil
}
func (em *ExpireMap) Increment(key string) error {
return em.add(key, 1)
}
func (em *ExpireMap) Decrement(key string) error {
return em.add(key, -1)
}
+func (em *ExpireMap) cycle() {
+ for {
+ select {
+ case <-em.stop:
+ return
+ default:
+ for key, expireTime := range em.expireTimes {
+ if !(time.Now().Before(expireTime)) {
+ em.mtx.Lock()
+ delete(em.expireTimes, key)
+ delete(em.m, key)
+ em.mtx.Unlock()
+ go func(key string) {
+ em.expired <- key
+ }(key)
+ }
+ }
+ }
+ }
+}
+
+func (em *ExpireMap) sendExpired() {
+ for {
+ select {
+ case expired := <-em.expired:
+ for _, c := range em.expiredListeners {
+ go func(c chan string) {
+ c <- expired
+ }(c)
+ }
+ case <-em.stop:
+ for _, c := range em.expiredListeners {
+ close(c)
+ }
+ return
+ }
+ }
+}
+
func (em *ExpireMap) add(key string, toAdd int) error {
+ defer em.mtx.Unlock()
+ em.mtx.Lock()
intValue, found := em.GetInt(key)
if found {
em.m[key] = intValue + toAdd
return nil
}
stringValue, found := em.GetString(key)
if found {
intValue, err := strconv.Atoi(stringValue)
if err != nil {
return err
}
em.m[key] = strconv.Itoa(intValue + toAdd)
return nil
}
return errors.New(fmt.Sprintf("There is no value for key %s.", key))
}