func (store *Store) Exchange(oldID, newID interface{}) error {
	store.Lock()
	defer store.Unlock()
	index, ok := store.ids[oldID]
	if !ok {
		return nil  
	}
	if _, ok := store.ids[newID]; ok {
		return fmt.Errorf("Cannot exchange ID, %s already exists", newID)
	}
	delete(store.ids, oldID)
	store.ids[newID] = index
	store.candidates[index].id = newID
	store.modified = true
	return nil
}
Exchange exchanges the ID of an image for a new one. If the old ID could not
be found, nothing happens. If the new ID already existed prior to the
exchange, an error is returned.
package duplo
import (
	"bytes"
	"compress/gzip"
	"encoding/gob"
	"fmt"
	"math"
	"sync"
	"github.com/rivo/duplo/haar"
)
const (
	ImageScale = 128
)
var (
	TopCoefs = 40
	weights = [3][6]float64{
		{5.00, 0.83, 1.01, 0.52, 0.47, 0.30},
		{19.21, 1.26, 0.44, 0.53, 0.28, 0.14},
		{34.37, 0.36, 0.45, 0.14, 0.18, 0.27},
	}
	weightSums = [6]float64{58.58, 2.45, 1.9, 1.19, 0.93, 0.71}
)
type Store struct {
	sync.RWMutex
	candidates []candidate
	ids map[interface{}]uint32
	indices [][]uint32
	modified bool
}
func New() *Store {
	store := new(Store)
	store.ids = make(map[interface{}]uint32)
	store.indices = make([][]uint32, 2*ImageScale*ImageScale*haar.ColourChannels)
	return store
}
func (store *Store) Has(id interface{}) bool {
	store.RLock()
	defer store.RUnlock()
	_, ok := store.ids[id]
	return ok
}
func (store *Store) Add(id interface{}, hash Hash) {
	store.Lock()
	defer store.Unlock()
	_, ok := store.ids[id]
	if ok {
		return
	}
	gob.Register(id)
	index := len(store.candidates)
	store.candidates = append(store.candidates, candidate{
		id,
		hash.Coefs[0],
		hash.Ratio,
		hash.DHash,
		hash.Histogram,
		hash.HistoMax})
	store.ids[id] = uint32(index)
	for coefIndex, coef := range hash.Coefs {
		if coefIndex == 0 {
			continue
		}
		for colourIndex, colourCoef := range coef {
			if math.Abs(colourCoef) < hash.Thresholds[colourIndex] {
				continue
			}
			sign := 0
			if colourCoef < 0 {
				sign = 1
			}
			location := sign*ImageScale*ImageScale*haar.ColourChannels + coefIndex*haar.ColourChannels + colourIndex
			store.indices[location] = append(store.indices[location], uint32(index))
		}
	}
	store.modified = true
}
func (store *Store) IDs() (ids []interface{}) {
	store.Lock()
	defer store.Unlock()
	for id := range store.ids {
		ids = append(ids, id)
	}
	return
}
func (store *Store) Delete(id interface{}) {
	store.Lock()
	defer store.Unlock()
	index, ok := store.ids[id]
	if !ok {
		return  
	}
	store.modified = true
	store.candidates[index].id = nil
	delete(store.ids, id)
	for location, list := range store.indices {
		for indexIndex := range list {
			if list[indexIndex] == index {
				store.indices[location] = append(list[:indexIndex], list[indexIndex+1:]...)
				break
			}
		}
	}
}