1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.build.apkzlib.zip;
18 
19 import com.google.common.base.MoreObjects;
20 import com.google.common.base.Preconditions;
21 import com.google.common.primitives.Ints;
22 import java.util.Comparator;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 
26 /**
27  * Represents an entry in the {@link FileUseMap}. Each entry contains an interval of bytes. The
28  * end of the interval is exclusive.
29  * <p>
30  * Entries can either be free or used. Used entries <em>must</em> store an object. Free entries
31  * do not store anything.
32  * <p>
33  * File map entries are used to keep track of which parts of a file map are used and not.
34  * @param <T> the type of data stored
35  */
36 class FileUseMapEntry<T> {
37 
38     /**
39      * Comparator that compares entries by their start date.
40      */
41     public static final Comparator<FileUseMapEntry<?>> COMPARE_BY_START =
42             (o1, o2) -> Ints.saturatedCast(o1.getStart() - o2.getStart());
43 
44     /**
45      * Comparator that compares entries by their size.
46      */
47     public static final Comparator<FileUseMapEntry<?>> COMPARE_BY_SIZE =
48             (o1, o2) -> Ints.saturatedCast(o1.getSize() - o2.getSize());
49 
50     /**
51      * The first byte in the entry.
52      */
53     private final long start;
54 
55     /**
56      * The first byte no longer in the entry.
57      */
58     private final long end;
59 
60     /**
61      * The stored data. If {@code null} then this entry represents a free entry.
62      */
63     @Nullable
64     private final T store;
65 
66     /**
67      * Creates a new map entry.
68      *
69      * @param start the start of the entry
70      * @param end the end of the entry (first byte no longer in the entry)
71      * @param store the data to store in the entry or {@code null} if this is a free entry
72      */
FileUseMapEntry(long start, long end, @Nullable T store)73     private FileUseMapEntry(long start, long end, @Nullable T store) {
74         Preconditions.checkArgument(start >= 0, "start < 0");
75         Preconditions.checkArgument(end > start, "end <= start");
76 
77         this.start = start;
78         this.end = end;
79         this.store = store;
80     }
81 
82     /**
83      * Creates a new free entry.
84      *
85      * @param start the start of the entry
86      * @param end the end of the entry (first byte no longer in the entry)
87      * @return the entry
88      */
makeFree(long start, long end)89     public static FileUseMapEntry<Object> makeFree(long start, long end) {
90         return new FileUseMapEntry<>(start, end, null);
91     }
92 
93     /**
94      * Creates a new used entry.
95      *
96      * @param start the start of the entry
97      * @param end the end of the entry (first byte no longer in the entry)
98      * @param store the data to store in the entry
99      * @param <T> the type of data to store in the entry
100      * @return the entry
101      */
makeUsed(long start, long end, @Nonnull T store)102     public static <T> FileUseMapEntry<T> makeUsed(long start, long end, @Nonnull T store) {
103         Preconditions.checkNotNull(store, "store == null");
104         return new FileUseMapEntry<>(start, end, store);
105     }
106 
107     /**
108      * Obtains the first byte in the entry.
109      *
110      * @return the first byte in the entry (if the same value as {@link #getEnd()} then the entry
111      * is empty and contains no data)
112      */
getStart()113     long getStart() {
114         return start;
115     }
116 
117     /**
118      * Obtains the first byte no longer in the entry.
119      *
120      * @return the first byte no longer in the entry
121      */
getEnd()122     long getEnd() {
123         return end;
124     }
125 
126     /**
127      * Obtains the size of the entry.
128      *
129      * @return the number of bytes contained in the entry
130      */
getSize()131     long getSize() {
132         return end - start;
133     }
134 
135     /**
136      * Determines if this is a free entry.
137      *
138      * @return is this entry free?
139      */
isFree()140     boolean isFree() {
141         return store == null;
142     }
143 
144     /**
145      * Obtains the data stored in the entry.
146      *
147      * @return the data stored or {@code null} if this entry is a free entry
148      */
149     @Nullable
getStore()150     T getStore() {
151         return store;
152     }
153 
154     @Override
toString()155     public String toString() {
156         return MoreObjects.toStringHelper(this)
157                 .add("start", start)
158                 .add("end", end)
159                 .add("store", store)
160                 .toString();
161     }
162 }
163