View Javadoc

1   /*-
2    * #%L
3    * prolobjectlink-jpi-jpl7
4    * %%
5    * Copyright (C) 2020 - 2021 Prolobjectlink Project
6    * %%
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions are met:
9    * 
10   * 1. Redistributions of source code must retain the above copyright notice,
11   *    this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright notice,
13   *    this list of conditions and the following disclaimer in the documentation
14   *    and/or other materials provided with the distribution.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * #L%
28   */
29  package io.github.prolobjectlink.prolog.jpl7;
30  
31  import java.util.Collection;
32  import java.util.Iterator;
33  import java.util.LinkedHashMap;
34  import java.util.LinkedHashSet;
35  import java.util.Map;
36  import java.util.Set;
37  
38  import io.github.prolobjectlink.prolog.AbstractCompounds;
39  import io.github.prolobjectlink.prolog.AbstractIterator;
40  import io.github.prolobjectlink.prolog.PrologMap;
41  import io.github.prolobjectlink.prolog.PrologProvider;
42  import io.github.prolobjectlink.prolog.PrologTerm;
43  import io.github.prolobjectlink.prolog.PrologTermType;
44  
45  /**
46   * A PrologTerm that maps PrologTerm keys to PrologTerm values. A map cannot
47   * contain duplicate keys. Each key can map to at most one value.
48   * 
49   * @author Jose Zalacain
50   * @since 1.1
51   */
52  public final class JplMap extends AbstractCompounds implements PrologMap {
53  
54  	private Map<PrologTerm, PrologTerm> map;
55  
56  	JplMap(PrologProvider provider, int size) {
57  		super(PrologTermType.MAP_TYPE, provider);
58  		map = new LinkedHashMap<PrologTerm, PrologTerm>(size);
59  	}
60  
61  	JplMap(PrologProvider provider, Map<? extends PrologTerm, ? extends PrologTerm> m) {
62  		this(provider);
63  		putAll(m);
64  	}
65  
66  	JplMap(PrologProvider provider) {
67  		this(provider, 16);
68  	}
69  
70  	public boolean isList() {
71  		return true;
72  	}
73  
74  	public boolean isStructure() {
75  		return false;
76  	}
77  
78  	public boolean isEmptyList() {
79  		return map.size() == 0;
80  	}
81  
82  	public String getFunctor() {
83  		return ".";
84  	}
85  
86  	public int getArity() {
87  		if (map.size() > 0) {
88  			return 2;
89  		}
90  		return 0;
91  	}
92  
93  	public PrologTerm[] getArguments() {
94  		PrologProvider p = getProvider();
95  		PrologTerm[] args = new PrologTerm[map.size()];
96  		Set<Entry<PrologTerm, PrologTerm>> s = entrySet();
97  		Iterator<Entry<PrologTerm, PrologTerm>> i = s.iterator();
98  		for (int j = 0; j < args.length && i.hasNext(); j++) {
99  			Entry<PrologTerm, PrologTerm> e = i.next();
100 			args[j] = new JplEntry(p, e.getKey(), e.getValue());
101 		}
102 		return args;
103 	}
104 
105 	public PrologTerm getArgument(int index) {
106 		int idx = 0;
107 		PrologTerm term = null;
108 		checkIndex(index, size());
109 		Iterator<PrologTerm> i = iterator();
110 		for (; i.hasNext() && idx <= index; idx++) {
111 			term = i.next();
112 			if (idx == index) {
113 				return term;
114 			}
115 		}
116 		return term;
117 	}
118 
119 	public int hashCode() {
120 		int result = 0;
121 		final int prime = 31;
122 		result = prime * result + ((map == null) ? 0 : map.hashCode());
123 		return result;
124 	}
125 
126 	public boolean equals(Object obj) {
127 		if (this == obj)
128 			return true;
129 		if (obj == null)
130 			return false;
131 		if (getClass() != obj.getClass())
132 			return false;
133 		JplMap other = (JplMap) obj;
134 		if (map == null) {
135 			if (other.map != null)
136 				return false;
137 		} else if (!map.equals(other.map)) {
138 			return false;
139 		}
140 		return true;
141 	}
142 
143 	@Override
144 	public String toString() {
145 		StringBuilder b = new StringBuilder();
146 		Set<Entry<PrologTerm, PrologTerm>> set = entrySet();
147 		Iterator<Entry<PrologTerm, PrologTerm>> i = set.iterator();
148 		b.append('[');
149 		while (i.hasNext()) {
150 			Entry<PrologTerm, PrologTerm> entry = i.next();
151 			b.append(entry.getKey());
152 			b.append('-');
153 			b.append(entry.getValue());
154 			if (i.hasNext()) {
155 				b.append(',');
156 				b.append(' ');
157 			}
158 		}
159 		b.append(']');
160 		return "" + b + "";
161 	}
162 
163 	@Override
164 	public Iterator<PrologTerm> iterator() {
165 		return new PrologMapIterator();
166 	}
167 
168 	@Override
169 	public PrologTerm getHead() {
170 		return iterator().next();
171 	}
172 
173 	@Override
174 	public PrologTerm getTail() {
175 		JplMap m = new JplMap(provider, map);
176 		m.remove(((Entry<?, ?>) getHead()).getKey());
177 		return m;
178 	}
179 
180 	public void putAll(Collection<Entry<PrologTerm, PrologTerm>> entries) {
181 		for (Entry<PrologTerm, PrologTerm> entry : entries) {
182 			put(entry);
183 		}
184 	}
185 
186 	public boolean contains(Entry<PrologTerm, PrologTerm> entry) {
187 		PrologTerm value = get(entry.getKey());
188 		return value != null ? value.equals(entry.getValue()) : false;
189 	}
190 
191 	public void remove(Entry<PrologTerm, PrologTerm> entry) {
192 		remove(entry.getKey());
193 	}
194 
195 	public void put(Entry<PrologTerm, PrologTerm> entry) {
196 		put(entry.getKey(), entry.getValue());
197 	}
198 
199 	private class PrologMapIterator extends AbstractIterator<PrologTerm> implements Iterator<PrologTerm> {
200 
201 		private final Set<PrologTerm> set;
202 		private final Iterator<PrologTerm> itr;
203 
204 		private PrologMapIterator() {
205 			set = new LinkedHashSet<PrologTerm>(map.size());
206 			for (Iterator<Entry<PrologTerm, PrologTerm>> i = map.entrySet().iterator(); i.hasNext();) {
207 				Entry<PrologTerm, PrologTerm> e = i.next();
208 				PrologTerm t = new JplEntry(provider, e.getKey(), e.getValue());
209 				set.add(t);
210 			}
211 			itr = set.iterator();
212 		}
213 
214 		@Override
215 		public boolean hasNext() {
216 			return itr.hasNext();
217 		}
218 
219 		@Override
220 		public PrologTerm next() {
221 			return itr.next();
222 		}
223 
224 	}
225 
226 	public PrologTerm put(PrologTerm key, PrologTerm value) {
227 		return map.put(key, value);
228 	}
229 
230 	public Set<Entry<PrologTerm, PrologTerm>> entrySet() {
231 		return map.entrySet();
232 	}
233 
234 	@Override
235 	public boolean containsKey(Object key) {
236 		return map.containsKey(key);
237 	}
238 
239 	@Override
240 	public boolean containsValue(Object value) {
241 		return map.containsValue(value);
242 	}
243 
244 	@Override
245 	public PrologTerm get(Object key) {
246 		return map.get(key);
247 	}
248 
249 	@Override
250 	public PrologTerm remove(Object key) {
251 		return map.remove(key);
252 	}
253 
254 	@Override
255 	public void putAll(Map<? extends PrologTerm, ? extends PrologTerm> m) {
256 		map.putAll(m);
257 	}
258 
259 	@Override
260 	public Set<PrologTerm> keySet() {
261 		return map.keySet();
262 	}
263 
264 	@Override
265 	public Collection<PrologTerm> values() {
266 		return map.values();
267 	}
268 
269 	@Override
270 	public boolean isEmpty() {
271 		return map.isEmpty();
272 	}
273 
274 	@Override
275 	public void clear() {
276 		map.clear();
277 	}
278 
279 	@Override
280 	public int size() {
281 		return map.size();
282 	}
283 
284 }