cache.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Copyright 2024 The Ebitengine Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package text
  15. import (
  16. "math"
  17. "sync"
  18. "sync/atomic"
  19. "github.com/hajimehoshi/ebiten/v2/internal/hook"
  20. )
  21. var monotonicClock atomic.Int64
  22. const infTime = math.MaxInt64
  23. func init() {
  24. hook.AppendHookOnBeforeUpdate(func() error {
  25. monotonicClock.Add(1)
  26. return nil
  27. })
  28. }
  29. type cacheValue[Value any] struct {
  30. value Value
  31. // atime is the last time when the value was accessed.
  32. atime int64
  33. }
  34. type cache[Key comparable, Value any] struct {
  35. // softLimit indicates the soft limit of the number of values in the cache.
  36. softLimit int
  37. values map[Key]*cacheValue[Value]
  38. // atime is the last time when the cache was accessed.
  39. atime int64
  40. m sync.Mutex
  41. }
  42. func newCache[Key comparable, Value any](softLimit int) *cache[Key, Value] {
  43. return &cache[Key, Value]{
  44. softLimit: softLimit,
  45. }
  46. }
  47. func (c *cache[Key, Value]) getOrCreate(key Key, create func() (Value, bool)) Value {
  48. n := monotonicClock.Load()
  49. c.m.Lock()
  50. defer c.m.Unlock()
  51. e, ok := c.values[key]
  52. if ok {
  53. e.atime = n
  54. return e.value
  55. }
  56. if c.values == nil {
  57. c.values = map[Key]*cacheValue[Value]{}
  58. }
  59. ent, canExpire := create()
  60. e = &cacheValue[Value]{
  61. value: ent,
  62. atime: infTime,
  63. }
  64. if canExpire {
  65. e.atime = n
  66. }
  67. c.values[key] = e
  68. // Clean up old entries.
  69. if c.atime < n {
  70. // If the number of values exceeds the soft limits, old values are removed.
  71. // Even after cleaning up the cache, the number of values might still exceed the soft limit,
  72. // but this is fine.
  73. if len(c.values) > c.softLimit {
  74. for key, e := range c.values {
  75. // 60 is an arbitrary number.
  76. if e.atime >= n-60 {
  77. continue
  78. }
  79. delete(c.values, key)
  80. }
  81. }
  82. }
  83. c.atime = n
  84. return e.value
  85. }