Решение на ExpireMap от Ясен Висулчев

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

Към профила на Ясен Висулчев

Резултати

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

Код

//Written by Yasen Visulchev for FMI/GOLANG
/*
{
"FacultyNumber": 81236
"FirstName": "Yasen"
"LastName": "Visulchev"
"AcademicYear": 2
"Master": false
}
*/
//16/11/2014
//how to channel
package main
import (
"errors"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
//ExpireMap implements a map with expiring keys.
type ExpireMap struct {
dict map[string]expireValue
rwm sync.RWMutex
echan chan string
sleeperKiller chan interface{}
echanCounter int
sleeperCounter int
wg sync.WaitGroup //Used to wait for echanners to finish trying to write in a channel.
trulyDead bool
}
//ExpireVal houses the values and their times of expiration.
type expireValue struct {
v interface{}
expire time.Time
}
//Returns a brand new ExpireMap, not truly dead!
func NewExpireMap() *ExpireMap {
var em ExpireMap
em.dict = make(map[string]expireValue)
em.echan = make(chan string, 1)
em.sleeperKiller = make(chan interface{})
em.echanCounter = 0
em.sleeperCounter = 0
em.trulyDead = false
return &em
}
//Adds a new key to the ExpireMap, with an expiration duration.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.rwm.Lock()
defer em.rwm.Unlock()
var a expireValue
a.v = value
a.expire = time.Now().Add(expire)
em.dict[key] = a
go func(em *ExpireMap, key string) {
em.sleeperCounter++
select {
case <-em.sleeperKiller:
em.sleeperCounter--
return
case <-time.After(expire):
em.sleeperCounter--
if _, ok := em.Get(key); ok && !em.trulyDead {
em.wg.Add(1)
em.echanCounter++
em.Delete(key)
em.echan <- key
em.echanCounter--
em.wg.Done()
}
}
}(em, key)
}
//Fetches value from the ExpireMap.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
i, ok := em.dict[key]
return i.v, ok
}
//Fetches integer value from the ExpireMap.
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(1)) {
return i.v.(int), ok
}
return 0, false
}
//Fetches float64 value from the ExpireMap.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
var check float64
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(check)) {
return i.v.(float64), ok
}
return 0, false
}
//Fetches string value from the ExpireMap.
func (em *ExpireMap) GetString(key string) (string, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf("")) {
return i.v.(string), ok
}
return "", false
}
//Fetches boolean value from the ExpireMap.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(false)) {
return i.v.(bool), ok
}
return false, false
}
//Returns the expiration time of the key.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok {
return i.expire, ok
}
var a time.Time
return a, false
}
//Deletes key and values from all structures of ExpireMap.
func (em *ExpireMap) Delete(key string) {
em.rwm.Lock()
defer em.rwm.Unlock()
delete(em.dict, key)
}
//States whether ExpireMap contains specified key.
func (em *ExpireMap) Contains(key string) bool {
em.rwm.RLock()
defer em.rwm.RUnlock()
_, ok := em.dict[key]
return ok
}
//Returns the size of the ExpireMap.
func (em *ExpireMap) Size() int {
em.rwm.Lock()
defer em.rwm.Unlock()
return len(em.dict)
}
//Increments integer values and string-integer values of the ExpireMap.
func (em *ExpireMap) Increment(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) + 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp + 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Decrements similarly to Increment.
func (em *ExpireMap) Decrement(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) - 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp - 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Capitalizes letters of string values.
func (em *ExpireMap) ToUpper(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToUpper(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Un-capitalizes letters of string values.
func (em *ExpireMap) ToLower(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToLower(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Returns a channel where expiring keys are reported.
//(Only expiring keys - not ones being deleted.)
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.echan
}
//Clears all internal storage of the ExpireMap.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.dict {
em.Delete(key)
}
}
//Clears all internal storage of the ExpireMap and closes down all assets.
func (em *ExpireMap) Destroy() {
em.trulyDead = true
var a interface{}
for i := 0; i < em.sleeperCounter; i++ {
em.sleeperKiller <- a
}
em.echan = make(chan string, em.echanCounter)
em.wg.Wait()
em.Cleanup()
close(em.echan)
close(em.sleeperKiller)
}

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

PASS
ok  	_/tmp/d20141204-6466-fus44x	0.015s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.017s
panic: test timed out

goroutine 15 [running]:
testing.alarm()
	/usr/local/lib/go/src/pkg/testing/testing.go:533 +0x44
created by time.goFunc
	/usr/local/lib/go/src/pkg/time/sleep.go:122 +0x45

goroutine 1 [chan receive]:
testing.RunTests(0x8148c90, 0x81c2ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148c90, 0x81c2ba0, 0x19, 0x19, 0x81c5600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-fus44x/_test/_testmain.go:91 +0x81

goroutine 4 [sleep]:
time.Sleep(0x3c336080, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-fus44x.TestSizes(0x183611e0)
	/tmp/d20141204-6466-fus44x/solution_test.go:111 +0x3d9
testing.tRunner(0x183611e0, 0x81c2bb8)
	/usr/local/lib/go/src/pkg/testing/testing.go:353 +0x87
created by testing.RunTests
	/usr/local/lib/go/src/pkg/testing/testing.go:433 +0x684

goroutine 5 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x18300268, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 6 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x18300290, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 7 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x183002b8, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 8 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x183002e0, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 9 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x18300308, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 10 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x18300330, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 11 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x18300358, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 12 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x18300380, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 13 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x183003a8, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 14 [runnable]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834e0a0, 0x183003d0, 0x5)
	/tmp/d20141204-6466-fus44x/solution.go:64 +0x19b
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166
exit status 2
FAIL	_/tmp/d20141204-6466-fus44x	1.013s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.122s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.175s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.016s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
--- FAIL: TestSimpleIncrementAndDecrementCalls-2 (0.00 seconds)
	solution_test.go:288: Decrementing non-number value did not return error
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-fus44x	0.012s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
--- FAIL: TestIncAndDecInManyRoutines-2 (0.05 seconds)
	solution_test.go:388: Expected 666 but found 2468
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-fus44x	0.060s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.112s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.062s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-fus44x	0.072s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.112s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.132s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.259s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
--- FAIL: TestDestroyMethodClosesExpireChannel-2 (0.05 seconds)
	solution_test.go:818: Expire channel was not closed in time
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-fus44x	0.062s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s
panic: test timed out

goroutine 20 [running]:
testing.alarm()
	/usr/local/lib/go/src/pkg/testing/testing.go:533 +0x44
created by time.goFunc
	/usr/local/lib/go/src/pkg/time/sleep.go:122 +0x45

goroutine 1 [chan receive]:
testing.RunTests(0x8148c90, 0x81c2ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148c90, 0x81c2ba0, 0x19, 0x19, 0x81c5600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-fus44x/_test/_testmain.go:91 +0x81

goroutine 4 [semacquire]:
sync.runtime_Semacquire(0x18300268)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*WaitGroup).Wait(0x1834ea2c)
	/usr/local/lib/go/src/pkg/sync/waitgroup.go:109 +0xda
_/tmp/d20141204-6466-fus44x.(*ExpireMap).Destroy(0x1834ea00)
	/tmp/d20141204-6466-fus44x/solution.go:260 +0xa8
_/tmp/d20141204-6466-fus44x.TestMultipleKeysWithTheSameExpireTime(0x1837c120)
	/tmp/d20141204-6466-fus44x/solution_test.go:892 +0x74e
testing.tRunner(0x1837c120, 0x81c2cb4)
	/usr/local/lib/go/src/pkg/testing/testing.go:353 +0x87
created by testing.RunTests
	/usr/local/lib/go/src/pkg/testing/testing.go:433 +0x684

goroutine 5 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351200, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 6 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351210, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 7 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351230, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 8 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351240, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 9 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351250, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 10 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351260, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 11 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351270, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 13 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18351290, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 14 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x183512a0, 0xf)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 15 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18331840, 0x10)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 16 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18331860, 0x10)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 17 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x18331880, 0x10)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 18 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x183318a0, 0x10)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166

goroutine 19 [chan send]:
_/tmp/d20141204-6466-fus44x.func·001(0x1834ea00, 0x183318c0, 0x10)
	/tmp/d20141204-6466-fus44x/solution.go:74 +0x16e
created by _/tmp/d20141204-6466-fus44x.(*ExpireMap).Set
	/tmp/d20141204-6466-fus44x/solution.go:80 +0x166
exit status 2
FAIL	_/tmp/d20141204-6466-fus44x	1.013s
PASS
ok  	_/tmp/d20141204-6466-fus44x	0.012s

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

Ясен обнови решението на 16.11.2014 19:18 (преди над 3 години)

+//Written by Yasen Visulchev for FMI/GOLANG
+/*
+{
+ "FacultyNumber": 81236
+ "FirstName": "Yasen"
+ "LastName": "Visulchev"
+ "AcademicYear": 2
+ "Master": false
+}
+*/
+//16/11/2014
+//how to channel
+package main
+
+import (
+ "errors"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+//ExpireMap implements a map with expiring keys.
+type ExpireMap struct {
+ dict map[string]interface{}
+ expireDict map[string]time.Time
+ rwm sync.RWMutex
+ echan chan string
+ trulyDead bool
+}
+
+//Returns a brand new ExpireMap, not truly dead!
+func NewExpireMap() *ExpireMap {
+ var em ExpireMap
+ em.dict = make(map[string]interface{})
+ em.expireDict = make(map[string]time.Time)
+ em.echan = make(chan string, 1)
+ em.trulyDead = false
+ return &em
+}
+
+//Adds a new key to the ExpireMap, with an expiration duration.
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
+ em.dict[key] = value
+ em.expireDict[key] = time.Now().Add(expire)
+ go func(em *ExpireMap, key string) {
+ time.Sleep(expire)
+ if _, ok := em.Get(key); ok && !em.trulyDead {
+ em.echan <- key
+ em.Delete(key)
+ }
+ }(em, key)
+}
+
+//Fetches value from the ExpireMap.
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
+ i, ok := em.dict[key]
+ return i, ok
+}
+
+//Fetches integer value from the ExpireMap.
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(1)) {
+ return i.(int), ok
+ }
+ return 0, false
+}
+
+//Fetches float64 value from the ExpireMap.
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
+ var check float64
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(check)) {
+ return i.(float64), ok
+ }
+ return 0, false
+}
+
+//Fetches string value from the ExpireMap.
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf("")) {
+ return i.(string), ok
+ }
+ return "", false
+}
+
+//Fetches boolean value from the ExpireMap.
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(false)) {
+ return i.(bool), ok
+ }
+ return false, false
+}
+
+//Returns the expiration time of the key.
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
+ if i, ok := em.expireDict[key]; ok {
+ return i, ok
+ }
+ var a time.Time
+ return a, false
+}
+
+//Deletes key and values from all structures of ExpireMap.
+func (em *ExpireMap) Delete(key string) {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
+ delete(em.dict, key)
+ delete(em.expireDict, key)
+}
+
+//States whether ExpireMap contains specified key.
+func (em *ExpireMap) Contains(key string) bool {
+ _, ok := em.dict[key]
+ return ok
+}
+
+//Returns the size of the ExpireMap.
+func (em *ExpireMap) Size() int {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
+ return len(em.dict)
+}
+
+//Increments integer values and string-integer values of the ExpireMap.
+func (em *ExpireMap) Increment(key string) error {
+ if _, ok := em.dict[key]; !ok {
+ return errors.New("No such key in ExpireMap")
+ }
+ if reflect.TypeOf(em.dict[key]) == reflect.TypeOf(0) {
+ em.dict[key] = em.dict[key].(int) + 1
+ return nil
+ } else if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
+ temp, err := strconv.Atoi(em.dict[key].(string))
+ em.dict[key] = strconv.Itoa(temp + 1)
+ return err
+ }
+ return errors.New("Value not an int or string.")
+}
+
+//Decrements similarly to Increment.
+func (em *ExpireMap) Decrement(key string) error {
+ if _, ok := em.dict[key]; !ok {
+ return errors.New("No such key in ExpireMap")
+ }
+ if reflect.TypeOf(em.dict[key]) == reflect.TypeOf(0) {
+ em.dict[key] = em.dict[key].(int) - 1
+ return nil
+ } else if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
+ temp, err := strconv.Atoi(em.dict[key].(string))
+ em.dict[key] = strconv.Itoa(temp - 1)
+ return err
+ }
+ return errors.New("Value not an int or string.")
+}
+
+//Capitalizes letters of string values.
+func (em *ExpireMap) ToUpper(key string) error {
+ if _, ok := em.dict[key]; !ok {
+ return errors.New("No such key in ExpireMap")
+ }
+ if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
+ em.dict[key] = strings.ToUpper(em.dict[key].(string))
+ return nil
+ }
+ return errors.New("Value not a string.")
+}
+
+//Un-capitalizes letters of string values.
+func (em *ExpireMap) ToLower(key string) error {
+ if _, ok := em.dict[key]; !ok {
+ return errors.New("No such key in ExpireMap")
+ }
+ if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
+ em.dict[key] = strings.ToLower(em.dict[key].(string))
+ return nil
+ }
+ return errors.New("Value not a string.")
+}
+
+//Returns a channel where expiring keys are reporter.
+//(Only expiring keys - not ones being deleted.)
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.echan
+}
+
+//Clears all internal storage of the ExpireMap.
+func (em *ExpireMap) Cleanup() {
+ for key, _ := range em.dict {
+ em.Delete(key)
+ }
+}
+
+//Clears all internal storage of the ExpireMap and closes down all assets.
+func (em *ExpireMap) Destroy() {
+ em.trulyDead = true
+ em.Cleanup()
+ close(em.echan)
+}

Ясен обнови решението на 16.11.2014 19:24 (преди над 3 години)

//Written by Yasen Visulchev for FMI/GOLANG
/*
{
"FacultyNumber": 81236
"FirstName": "Yasen"
"LastName": "Visulchev"
"AcademicYear": 2
"Master": false
}
*/
//16/11/2014
//how to channel
package main
import (
"errors"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
//ExpireMap implements a map with expiring keys.
type ExpireMap struct {
dict map[string]interface{}
expireDict map[string]time.Time
rwm sync.RWMutex
echan chan string
trulyDead bool
}
//Returns a brand new ExpireMap, not truly dead!
func NewExpireMap() *ExpireMap {
var em ExpireMap
em.dict = make(map[string]interface{})
em.expireDict = make(map[string]time.Time)
em.echan = make(chan string, 1)
em.trulyDead = false
return &em
}
//Adds a new key to the ExpireMap, with an expiration duration.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.rwm.Lock()
defer em.rwm.Unlock()
em.dict[key] = value
em.expireDict[key] = time.Now().Add(expire)
go func(em *ExpireMap, key string) {
time.Sleep(expire)
if _, ok := em.Get(key); ok && !em.trulyDead {
- em.echan <- key
em.Delete(key)
+ em.echan <- key
}
}(em, key)
}
//Fetches value from the ExpireMap.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
i, ok := em.dict[key]
return i, ok
}
//Fetches integer value from the ExpireMap.
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(1)) {
return i.(int), ok
}
return 0, false
}
//Fetches float64 value from the ExpireMap.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
var check float64
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(check)) {
return i.(float64), ok
}
return 0, false
}
//Fetches string value from the ExpireMap.
func (em *ExpireMap) GetString(key string) (string, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf("")) {
return i.(string), ok
}
return "", false
}
//Fetches boolean value from the ExpireMap.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(false)) {
return i.(bool), ok
}
return false, false
}
//Returns the expiration time of the key.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.expireDict[key]; ok {
return i, ok
}
var a time.Time
return a, false
}
//Deletes key and values from all structures of ExpireMap.
func (em *ExpireMap) Delete(key string) {
em.rwm.Lock()
defer em.rwm.Unlock()
delete(em.dict, key)
delete(em.expireDict, key)
}
//States whether ExpireMap contains specified key.
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.dict[key]
return ok
}
//Returns the size of the ExpireMap.
func (em *ExpireMap) Size() int {
em.rwm.Lock()
defer em.rwm.Unlock()
return len(em.dict)
}
//Increments integer values and string-integer values of the ExpireMap.
func (em *ExpireMap) Increment(key string) error {
if _, ok := em.dict[key]; !ok {
- return errors.New("No such key in ExpireMap")
+ return errors.New("No such key in ExpireMap.")
}
if reflect.TypeOf(em.dict[key]) == reflect.TypeOf(0) {
em.dict[key] = em.dict[key].(int) + 1
return nil
} else if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
temp, err := strconv.Atoi(em.dict[key].(string))
em.dict[key] = strconv.Itoa(temp + 1)
return err
}
return errors.New("Value not an int or string.")
}
//Decrements similarly to Increment.
func (em *ExpireMap) Decrement(key string) error {
if _, ok := em.dict[key]; !ok {
- return errors.New("No such key in ExpireMap")
+ return errors.New("No such key in ExpireMap.")
}
if reflect.TypeOf(em.dict[key]) == reflect.TypeOf(0) {
em.dict[key] = em.dict[key].(int) - 1
return nil
} else if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
temp, err := strconv.Atoi(em.dict[key].(string))
em.dict[key] = strconv.Itoa(temp - 1)
return err
}
return errors.New("Value not an int or string.")
}
//Capitalizes letters of string values.
func (em *ExpireMap) ToUpper(key string) error {
if _, ok := em.dict[key]; !ok {
- return errors.New("No such key in ExpireMap")
+ return errors.New("No such key in ExpireMap.")
}
if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
em.dict[key] = strings.ToUpper(em.dict[key].(string))
return nil
}
return errors.New("Value not a string.")
}
//Un-capitalizes letters of string values.
func (em *ExpireMap) ToLower(key string) error {
if _, ok := em.dict[key]; !ok {
- return errors.New("No such key in ExpireMap")
+ return errors.New("No such key in ExpireMap.")
}
if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
em.dict[key] = strings.ToLower(em.dict[key].(string))
return nil
}
return errors.New("Value not a string.")
}
-//Returns a channel where expiring keys are reporter.
+//Returns a channel where expiring keys are reported.
//(Only expiring keys - not ones being deleted.)
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.echan
}
//Clears all internal storage of the ExpireMap.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.dict {
em.Delete(key)
}
}
//Clears all internal storage of the ExpireMap and closes down all assets.
func (em *ExpireMap) Destroy() {
em.trulyDead = true
em.Cleanup()
close(em.echan)
}

хм .... Не бих казал че ми харесва, но изглежда сравнително работещо ОСВЕН ... нека предположим че никой не чете от ExpiredChan ? какво ще се случи ? А ако никой не чете от него и ти викнеш Destroy след като някой ключ е expired-нал ? подсказка - втория sleep е за да не излезе преди горотината да се доопита да пише във вече затворения канал :).

Можеш да намалиш броя на map-овете които ползваш :)

Ех... жалко, че не ти харесва! :P

Ако предположим, че никой не чете от ExpiredChan, горутините си висят зациклили в опит да пишат в този чан (ExpireMap.echan). Както се разбрахме на лекциите, горутините не са много скъпи, така че нямам проблем с това да си висят до края на програмата.

ОБАЧЕ, както ми насочи вниманието:

Проверката за това дали е унищожен ExpireMap-a върши работа само в случая, че някой е решил да Expire-ва след спирането на цялата работа. Не върши работа за цялата опашка от хора, които вече чакат да пишат.

Това ще го оправям като предефинирам буфериран канал, който да поеме всичките им заявки, точно преди да затворя всичко.

;)

Type switch ще го прилагам на място, също.

За да не използвам два мапа, ще си направя структ, който да съдържа:

interface{}
time.Duration expiration

И тъй!

Благодаря за фийдбека! :)

Реших да не използвам type switch, защото поради някаква причина смята, че променливата, по която switch-ва, не се използва (и не компилира кодът).

А аз всъщност бих я използвал тази променлива само за switch-ване.

Например:

switch p := мистерия.(type) {
default:
    fmt.Println("This is no type of mine!")
case int:
    fmt.Printf("This %v is one true int!\n", мистерия)
}

Хвърля, че p не се използва, а се декларира напразно! Ето тук е нагледно.

Ясен обнови решението на 17.11.2014 17:35 (преди над 3 години)

//Written by Yasen Visulchev for FMI/GOLANG
/*
{
"FacultyNumber": 81236
"FirstName": "Yasen"
"LastName": "Visulchev"
"AcademicYear": 2
"Master": false
}
*/
//16/11/2014
//how to channel
package main
import (
"errors"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
//ExpireMap implements a map with expiring keys.
type ExpireMap struct {
- dict map[string]interface{}
- expireDict map[string]time.Time
- rwm sync.RWMutex
- echan chan string
- trulyDead bool
+ dict map[string]expireValue
+ rwm sync.RWMutex
+ echan chan string
+ echanCounter int
+ wg sync.WaitGroup //Used to wait for echanners to finish trying to write in a channel.
+ trulyDead bool
}
+//ExpireVal houses the values and their times of expiration.
+type expireValue struct {
+ v interface{}
+ expire time.Time
+}
+
//Returns a brand new ExpireMap, not truly dead!
func NewExpireMap() *ExpireMap {
var em ExpireMap
- em.dict = make(map[string]interface{})
- em.expireDict = make(map[string]time.Time)
+ em.dict = make(map[string]expireValue)
em.echan = make(chan string, 1)
+ em.echanCounter = 0
em.trulyDead = false
return &em
}
//Adds a new key to the ExpireMap, with an expiration duration.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.rwm.Lock()
defer em.rwm.Unlock()
- em.dict[key] = value
- em.expireDict[key] = time.Now().Add(expire)
+ var a expireValue
+ a.v = value
+ a.expire = time.Now().Add(expire)
+ em.dict[key] = a
go func(em *ExpireMap, key string) {
time.Sleep(expire)
if _, ok := em.Get(key); ok && !em.trulyDead {
+ em.wg.Add(1)
+ em.echanCounter++
em.Delete(key)
em.echan <- key
+ em.echanCounter--
+ em.wg.Done()
}
}(em, key)
}
//Fetches value from the ExpireMap.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
i, ok := em.dict[key]
- return i, ok
+ return i.v, ok
}
//Fetches integer value from the ExpireMap.
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
- if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(1)) {
- return i.(int), ok
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(1)) {
+ return i.v.(int), ok
}
return 0, false
}
//Fetches float64 value from the ExpireMap.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
var check float64
- if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(check)) {
- return i.(float64), ok
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(check)) {
+ return i.v.(float64), ok
}
return 0, false
}
//Fetches string value from the ExpireMap.
func (em *ExpireMap) GetString(key string) (string, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
- if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf("")) {
- return i.(string), ok
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf("")) {
+ return i.v.(string), ok
}
return "", false
}
//Fetches boolean value from the ExpireMap.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
- if i, ok := em.dict[key]; ok && (reflect.TypeOf(i) == reflect.TypeOf(false)) {
- return i.(bool), ok
+ if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(false)) {
+ return i.v.(bool), ok
}
return false, false
}
//Returns the expiration time of the key.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
- if i, ok := em.expireDict[key]; ok {
- return i, ok
+ if i, ok := em.dict[key]; ok {
+ return i.expire, ok
}
var a time.Time
return a, false
}
//Deletes key and values from all structures of ExpireMap.
func (em *ExpireMap) Delete(key string) {
em.rwm.Lock()
defer em.rwm.Unlock()
delete(em.dict, key)
- delete(em.expireDict, key)
}
//States whether ExpireMap contains specified key.
func (em *ExpireMap) Contains(key string) bool {
_, ok := em.dict[key]
return ok
}
//Returns the size of the ExpireMap.
func (em *ExpireMap) Size() int {
em.rwm.Lock()
defer em.rwm.Unlock()
return len(em.dict)
}
//Increments integer values and string-integer values of the ExpireMap.
func (em *ExpireMap) Increment(key string) error {
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
- if reflect.TypeOf(em.dict[key]) == reflect.TypeOf(0) {
- em.dict[key] = em.dict[key].(int) + 1
+ a := em.dict[key]
+ if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
+ a.v = a.v.(int) + 1
+ em.dict[key] = a
return nil
- } else if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
- temp, err := strconv.Atoi(em.dict[key].(string))
- em.dict[key] = strconv.Itoa(temp + 1)
+ } else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
+ temp, err := strconv.Atoi(a.v.(string))
+ a.v = strconv.Itoa(temp + 1)
+ em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Decrements similarly to Increment.
func (em *ExpireMap) Decrement(key string) error {
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
- if reflect.TypeOf(em.dict[key]) == reflect.TypeOf(0) {
- em.dict[key] = em.dict[key].(int) - 1
+ a := em.dict[key]
+ if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
+ a.v = a.v.(int) - 1
+ em.dict[key] = a
return nil
- } else if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
- temp, err := strconv.Atoi(em.dict[key].(string))
- em.dict[key] = strconv.Itoa(temp - 1)
+ } else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
+ temp, err := strconv.Atoi(a.v.(string))
+ a.v = strconv.Itoa(temp - 1)
+ em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Capitalizes letters of string values.
func (em *ExpireMap) ToUpper(key string) error {
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
- if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
- em.dict[key] = strings.ToUpper(em.dict[key].(string))
+ a := em.dict[key]
+ if reflect.TypeOf(a.v) == reflect.TypeOf("") {
+ a.v = strings.ToUpper(a.v.(string))
+ em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Un-capitalizes letters of string values.
func (em *ExpireMap) ToLower(key string) error {
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
- if reflect.TypeOf(em.dict[key]) == reflect.TypeOf("") {
- em.dict[key] = strings.ToLower(em.dict[key].(string))
+ a := em.dict[key]
+ if reflect.TypeOf(a.v) == reflect.TypeOf("") {
+ a.v = strings.ToLower(a.v.(string))
+ em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Returns a channel where expiring keys are reported.
//(Only expiring keys - not ones being deleted.)
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.echan
}
//Clears all internal storage of the ExpireMap.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.dict {
em.Delete(key)
}
}
//Clears all internal storage of the ExpireMap and closes down all assets.
func (em *ExpireMap) Destroy() {
em.trulyDead = true
+ em.echan = make(chan string, em.echanCounter)
+ em.wg.Wait()
em.Cleanup()
close(em.echan)
}

Ясен обнови решението на 17.11.2014 17:40 (преди над 3 години)

//Written by Yasen Visulchev for FMI/GOLANG
/*
{
"FacultyNumber": 81236
"FirstName": "Yasen"
"LastName": "Visulchev"
"AcademicYear": 2
"Master": false
}
*/
//16/11/2014
//how to channel
package main
import (
"errors"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
//ExpireMap implements a map with expiring keys.
type ExpireMap struct {
dict map[string]expireValue
rwm sync.RWMutex
echan chan string
echanCounter int
wg sync.WaitGroup //Used to wait for echanners to finish trying to write in a channel.
trulyDead bool
}
//ExpireVal houses the values and their times of expiration.
type expireValue struct {
v interface{}
expire time.Time
}
//Returns a brand new ExpireMap, not truly dead!
func NewExpireMap() *ExpireMap {
var em ExpireMap
em.dict = make(map[string]expireValue)
em.echan = make(chan string, 1)
em.echanCounter = 0
em.trulyDead = false
return &em
}
//Adds a new key to the ExpireMap, with an expiration duration.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.rwm.Lock()
defer em.rwm.Unlock()
var a expireValue
a.v = value
a.expire = time.Now().Add(expire)
em.dict[key] = a
go func(em *ExpireMap, key string) {
time.Sleep(expire)
if _, ok := em.Get(key); ok && !em.trulyDead {
em.wg.Add(1)
em.echanCounter++
em.Delete(key)
em.echan <- key
em.echanCounter--
em.wg.Done()
}
}(em, key)
}
//Fetches value from the ExpireMap.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
i, ok := em.dict[key]
return i.v, ok
}
//Fetches integer value from the ExpireMap.
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(1)) {
return i.v.(int), ok
}
return 0, false
}
//Fetches float64 value from the ExpireMap.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
var check float64
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(check)) {
return i.v.(float64), ok
}
return 0, false
}
//Fetches string value from the ExpireMap.
func (em *ExpireMap) GetString(key string) (string, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf("")) {
return i.v.(string), ok
}
return "", false
}
//Fetches boolean value from the ExpireMap.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(false)) {
return i.v.(bool), ok
}
return false, false
}
//Returns the expiration time of the key.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok {
return i.expire, ok
}
var a time.Time
return a, false
}
//Deletes key and values from all structures of ExpireMap.
func (em *ExpireMap) Delete(key string) {
em.rwm.Lock()
defer em.rwm.Unlock()
delete(em.dict, key)
}
//States whether ExpireMap contains specified key.
func (em *ExpireMap) Contains(key string) bool {
+ em.rwm.RLock()
+ defer em.rwm.RUnlock()
_, ok := em.dict[key]
return ok
}
//Returns the size of the ExpireMap.
func (em *ExpireMap) Size() int {
em.rwm.Lock()
defer em.rwm.Unlock()
return len(em.dict)
}
//Increments integer values and string-integer values of the ExpireMap.
func (em *ExpireMap) Increment(key string) error {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) + 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp + 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Decrements similarly to Increment.
func (em *ExpireMap) Decrement(key string) error {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) - 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp - 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Capitalizes letters of string values.
func (em *ExpireMap) ToUpper(key string) error {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToUpper(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Un-capitalizes letters of string values.
func (em *ExpireMap) ToLower(key string) error {
+ em.rwm.Lock()
+ defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToLower(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Returns a channel where expiring keys are reported.
//(Only expiring keys - not ones being deleted.)
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.echan
}
//Clears all internal storage of the ExpireMap.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.dict {
em.Delete(key)
}
}
//Clears all internal storage of the ExpireMap and closes down all assets.
func (em *ExpireMap) Destroy() {
em.trulyDead = true
em.echan = make(chan string, em.echanCounter)
em.wg.Wait()
em.Cleanup()
close(em.echan)
}

Ясен обнови решението на 18.11.2014 15:37 (преди над 3 години)

//Written by Yasen Visulchev for FMI/GOLANG
/*
{
"FacultyNumber": 81236
"FirstName": "Yasen"
"LastName": "Visulchev"
"AcademicYear": 2
"Master": false
}
*/
//16/11/2014
//how to channel
package main
import (
"errors"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
//ExpireMap implements a map with expiring keys.
type ExpireMap struct {
- dict map[string]expireValue
- rwm sync.RWMutex
- echan chan string
- echanCounter int
- wg sync.WaitGroup //Used to wait for echanners to finish trying to write in a channel.
- trulyDead bool
+ dict map[string]expireValue
+ rwm sync.RWMutex
+ echan chan string
+ sleeperKiller chan interface{}
+ echanCounter int
+ sleeperCounter int
+ wg sync.WaitGroup //Used to wait for echanners to finish trying to write in a channel.
+ trulyDead bool
}
//ExpireVal houses the values and their times of expiration.
type expireValue struct {
v interface{}
expire time.Time
}
//Returns a brand new ExpireMap, not truly dead!
func NewExpireMap() *ExpireMap {
var em ExpireMap
em.dict = make(map[string]expireValue)
em.echan = make(chan string, 1)
+ em.sleeperKiller = make(chan interface{})
em.echanCounter = 0
+ em.sleeperCounter = 0
em.trulyDead = false
return &em
}
//Adds a new key to the ExpireMap, with an expiration duration.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.rwm.Lock()
defer em.rwm.Unlock()
var a expireValue
a.v = value
a.expire = time.Now().Add(expire)
em.dict[key] = a
go func(em *ExpireMap, key string) {
- time.Sleep(expire)
- if _, ok := em.Get(key); ok && !em.trulyDead {
- em.wg.Add(1)
- em.echanCounter++
- em.Delete(key)
- em.echan <- key
- em.echanCounter--
- em.wg.Done()
+ em.sleeperCounter++
+ select {
+ case <-em.sleeperKiller:
+ em.sleeperCounter--
+ return
+ case <-time.After(expire):
+ em.sleeperCounter--
+ if _, ok := em.Get(key); ok && !em.trulyDead {
+ em.wg.Add(1)
+ em.echanCounter++
+ em.Delete(key)
+ em.echan <- key
+ em.echanCounter--
+ em.wg.Done()
+ }
}
+
}(em, key)
}
//Fetches value from the ExpireMap.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
i, ok := em.dict[key]
return i.v, ok
}
//Fetches integer value from the ExpireMap.
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(1)) {
return i.v.(int), ok
}
return 0, false
}
//Fetches float64 value from the ExpireMap.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
var check float64
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(check)) {
return i.v.(float64), ok
}
return 0, false
}
//Fetches string value from the ExpireMap.
func (em *ExpireMap) GetString(key string) (string, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf("")) {
return i.v.(string), ok
}
return "", false
}
//Fetches boolean value from the ExpireMap.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(false)) {
return i.v.(bool), ok
}
return false, false
}
//Returns the expiration time of the key.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok {
return i.expire, ok
}
var a time.Time
return a, false
}
//Deletes key and values from all structures of ExpireMap.
func (em *ExpireMap) Delete(key string) {
em.rwm.Lock()
defer em.rwm.Unlock()
delete(em.dict, key)
}
//States whether ExpireMap contains specified key.
func (em *ExpireMap) Contains(key string) bool {
em.rwm.RLock()
defer em.rwm.RUnlock()
_, ok := em.dict[key]
return ok
}
//Returns the size of the ExpireMap.
func (em *ExpireMap) Size() int {
em.rwm.Lock()
defer em.rwm.Unlock()
return len(em.dict)
}
//Increments integer values and string-integer values of the ExpireMap.
func (em *ExpireMap) Increment(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) + 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp + 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Decrements similarly to Increment.
func (em *ExpireMap) Decrement(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) - 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp - 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Capitalizes letters of string values.
func (em *ExpireMap) ToUpper(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToUpper(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Un-capitalizes letters of string values.
func (em *ExpireMap) ToLower(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToLower(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Returns a channel where expiring keys are reported.
//(Only expiring keys - not ones being deleted.)
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.echan
}
//Clears all internal storage of the ExpireMap.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.dict {
em.Delete(key)
}
}
//Clears all internal storage of the ExpireMap and closes down all assets.
func (em *ExpireMap) Destroy() {
em.trulyDead = true
+ var a interface{}
+ for i := 0; i < em.sleeperCounter; i++ {
+ em.sleeperKiller <- a
+ }
em.echan = make(chan string, em.echanCounter)
em.wg.Wait()
em.Cleanup()
close(em.echan)
}

Ясен обнови решението на 18.11.2014 15:39 (преди над 3 години)

//Written by Yasen Visulchev for FMI/GOLANG
/*
{
"FacultyNumber": 81236
"FirstName": "Yasen"
"LastName": "Visulchev"
"AcademicYear": 2
"Master": false
}
*/
//16/11/2014
//how to channel
package main
import (
"errors"
"reflect"
"strconv"
"strings"
"sync"
"time"
)
//ExpireMap implements a map with expiring keys.
type ExpireMap struct {
dict map[string]expireValue
rwm sync.RWMutex
echan chan string
sleeperKiller chan interface{}
echanCounter int
sleeperCounter int
wg sync.WaitGroup //Used to wait for echanners to finish trying to write in a channel.
trulyDead bool
}
//ExpireVal houses the values and their times of expiration.
type expireValue struct {
v interface{}
expire time.Time
}
//Returns a brand new ExpireMap, not truly dead!
func NewExpireMap() *ExpireMap {
var em ExpireMap
em.dict = make(map[string]expireValue)
em.echan = make(chan string, 1)
em.sleeperKiller = make(chan interface{})
em.echanCounter = 0
em.sleeperCounter = 0
em.trulyDead = false
return &em
}
//Adds a new key to the ExpireMap, with an expiration duration.
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.rwm.Lock()
defer em.rwm.Unlock()
var a expireValue
a.v = value
a.expire = time.Now().Add(expire)
em.dict[key] = a
go func(em *ExpireMap, key string) {
em.sleeperCounter++
select {
case <-em.sleeperKiller:
em.sleeperCounter--
return
case <-time.After(expire):
em.sleeperCounter--
if _, ok := em.Get(key); ok && !em.trulyDead {
em.wg.Add(1)
em.echanCounter++
em.Delete(key)
em.echan <- key
em.echanCounter--
em.wg.Done()
}
}
}(em, key)
}
//Fetches value from the ExpireMap.
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
i, ok := em.dict[key]
return i.v, ok
}
//Fetches integer value from the ExpireMap.
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(1)) {
return i.v.(int), ok
}
return 0, false
}
//Fetches float64 value from the ExpireMap.
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
var check float64
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(check)) {
return i.v.(float64), ok
}
return 0, false
}
//Fetches string value from the ExpireMap.
func (em *ExpireMap) GetString(key string) (string, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf("")) {
return i.v.(string), ok
}
return "", false
}
//Fetches boolean value from the ExpireMap.
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok && (reflect.TypeOf(i.v) == reflect.TypeOf(false)) {
return i.v.(bool), ok
}
return false, false
}
//Returns the expiration time of the key.
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.rwm.RLock()
defer em.rwm.RUnlock()
if i, ok := em.dict[key]; ok {
return i.expire, ok
}
var a time.Time
return a, false
}
//Deletes key and values from all structures of ExpireMap.
func (em *ExpireMap) Delete(key string) {
em.rwm.Lock()
defer em.rwm.Unlock()
delete(em.dict, key)
}
//States whether ExpireMap contains specified key.
func (em *ExpireMap) Contains(key string) bool {
em.rwm.RLock()
defer em.rwm.RUnlock()
_, ok := em.dict[key]
return ok
}
//Returns the size of the ExpireMap.
func (em *ExpireMap) Size() int {
em.rwm.Lock()
defer em.rwm.Unlock()
return len(em.dict)
}
//Increments integer values and string-integer values of the ExpireMap.
func (em *ExpireMap) Increment(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) + 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp + 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Decrements similarly to Increment.
func (em *ExpireMap) Decrement(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf(0) {
a.v = a.v.(int) - 1
em.dict[key] = a
return nil
} else if reflect.TypeOf(a.v) == reflect.TypeOf("") {
temp, err := strconv.Atoi(a.v.(string))
a.v = strconv.Itoa(temp - 1)
em.dict[key] = a
return err
}
return errors.New("Value not an int or string.")
}
//Capitalizes letters of string values.
func (em *ExpireMap) ToUpper(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToUpper(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Un-capitalizes letters of string values.
func (em *ExpireMap) ToLower(key string) error {
em.rwm.Lock()
defer em.rwm.Unlock()
if _, ok := em.dict[key]; !ok {
return errors.New("No such key in ExpireMap.")
}
a := em.dict[key]
if reflect.TypeOf(a.v) == reflect.TypeOf("") {
a.v = strings.ToLower(a.v.(string))
em.dict[key] = a
return nil
}
return errors.New("Value not a string.")
}
//Returns a channel where expiring keys are reported.
//(Only expiring keys - not ones being deleted.)
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.echan
}
//Clears all internal storage of the ExpireMap.
func (em *ExpireMap) Cleanup() {
for key, _ := range em.dict {
em.Delete(key)
}
}
//Clears all internal storage of the ExpireMap and closes down all assets.
func (em *ExpireMap) Destroy() {
em.trulyDead = true
var a interface{}
for i := 0; i < em.sleeperCounter; i++ {
em.sleeperKiller <- a
}
em.echan = make(chan string, em.echanCounter)
em.wg.Wait()
em.Cleanup()
close(em.echan)
+ close(em.sleeperKiller)
}