// Copyright 2016 by Sascha L. Teichmann // Use of this source code is governed by the MIT license // that can be found in the LICENSE file. package common import ( "bytes" "sync" ) const btMaxEntries = 256 type btKey struct { x int y int } type btHashEntry struct { prev *btHashEntry next *btHashEntry hash []byte btKey } type BaseTileHash struct { hashes map[btKey]*btHashEntry root btHashEntry sync.Mutex } func NewBaseTileHash() *BaseTileHash { bth := &BaseTileHash{ hashes: map[btKey]*btHashEntry{}} bth.root.next = &bth.root bth.root.prev = &bth.root return bth } func (bth *BaseTileHash) toFront(entry *btHashEntry) { if bth.root.next == entry { return } entry.prev.next = entry.next entry.next.prev = entry.prev entry.next = bth.root.next entry.prev = &bth.root bth.root.next = entry } func (bth *BaseTileHash) removeLast() *btHashEntry { last := bth.root.prev bth.root.prev = last.prev last.prev.next = &bth.root delete(bth.hashes, last.btKey) return last } func (bth *BaseTileHash) insertFront(entry *btHashEntry) { entry.next = bth.root.next entry.prev = &bth.root bth.root.next.prev = entry bth.root.next = entry } func (bth *BaseTileHash) Update(x, y int, hash []byte) bool { bth.Lock() defer bth.Unlock() key := btKey{x, y} if old, found := bth.hashes[key]; found { if !bytes.Equal(old.hash, hash) { old.hash = hash bth.toFront(old) return true } return false } var entry *btHashEntry if len(bth.hashes) >= btMaxEntries { entry = bth.removeLast() } else { entry = new(btHashEntry) } entry.btKey = key entry.hash = hash bth.hashes[key] = entry bth.insertFront(entry) return true }