1package com.bumptech.glide.load.model;
2
3import com.bumptech.glide.util.LruCache;
4
5import java.util.ArrayDeque;
6import java.util.Queue;
7
8/**
9 * A simple cache that can be used by {@link ModelLoader} and {@link ModelLoaderFactory} to cache some data for a given
10 * model, width and height. For a loader that takes a model and returns a url, the cache could be used to safely memoize
11 * url creation based on the width and height of the view.
12 *
13 * @param <A> Some Model type that implements equals and hashcode.
14 * @param <B> Some useful type that may be expensive to create (URL, file path, etc).
15 * //TODO: fix this.
16 */
17public class ModelCache<A, B> {
18    private static final int DEFAULT_SIZE = 250;
19
20    private static class ModelKey<A> {
21        private static final Queue<ModelKey> KEY_QUEUE = new ArrayDeque<ModelKey>();
22
23        @SuppressWarnings("unchecked")
24        public static <A> ModelKey<A> get(A model, int width, int height) {
25            ModelKey<A> modelKey = KEY_QUEUE.poll();
26            if (modelKey == null) {
27                modelKey = new ModelKey<A>();
28            }
29
30            modelKey.init(model, width, height);
31            return modelKey;
32        }
33
34        private int height;
35        private int width;
36        private A model;
37
38        private ModelKey() {  }
39
40        private void init(A model, int width, int height) {
41            this.model = model;
42            this.width = width;
43            this.height = height;
44        }
45
46        public void release() {
47            KEY_QUEUE.offer(this);
48        }
49
50        @Override
51        public boolean equals(Object o) {
52            if (this == o) return true;
53            if (o == null || getClass() != o.getClass()) return false;
54
55            ModelKey modelKey = (ModelKey) o;
56
57            if (height != modelKey.height) return false;
58            if (width != modelKey.width) return false;
59            if (!model.equals(modelKey.model)) return false;
60
61            return true;
62        }
63
64        @Override
65        public int hashCode() {
66            int result = height;
67            result = 31 * result + width;
68            result = 31 * result + model.hashCode();
69            return result;
70        }
71    }
72
73    private final LruCache<ModelKey<A>, B> cache;
74
75    public ModelCache() {
76        this(DEFAULT_SIZE);
77    }
78
79    public ModelCache(int size) {
80        cache = new LruCache<ModelKey<A>, B>(size) {
81            @Override
82            protected void onItemRemoved(ModelKey<A> key, B item) {
83                key.release();
84            }
85        };
86    }
87
88    /**
89     * Get a value.
90     *
91     * @param model The model.
92     * @param width The width of the view the image is being loaded into.
93     * @param height The height of the view the image is being loaded into.
94     *
95     * @return The cached result, or null.
96     */
97    public B get(A model, int width, int height) {
98        ModelKey<A> key = ModelKey.get(model, width, height);
99        B result = cache.get(key);
100        key.release();
101        return result;
102    }
103
104    /**
105     * Add a value.
106     *
107     * @param model The model.
108     * @param width The width of the view the image is being loaded into.
109     * @param height The height of the view the image is being loaded into.
110     * @param value The value to store.
111     */
112    public void put(A model, int width, int height, B value) {
113        ModelKey<A> key = ModelKey.get(model, width, height);
114        cache.put(key, value);
115    }
116}
117