View Javadoc

1   /*-
2    * #%L
3    * prolobjectlink-jpi-jpl
4    * %%
5    * Copyright (C) 2020 - 2021 Prolobjectlink Project
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation, either version 2.1 of the
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
21   */
22  package io.github.prolobjectlink.prolog.jpl;
23  
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.LinkedHashMap;
27  import java.util.LinkedHashSet;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import io.github.prolobjectlink.prolog.AbstractCompounds;
32  import io.github.prolobjectlink.prolog.AbstractIterator;
33  import io.github.prolobjectlink.prolog.PrologMap;
34  import io.github.prolobjectlink.prolog.PrologProvider;
35  import io.github.prolobjectlink.prolog.PrologTerm;
36  import io.github.prolobjectlink.prolog.PrologTermType;
37  
38  /**
39   * A PrologTerm that maps PrologTerm keys to PrologTerm values. A map cannot
40   * contain duplicate keys. Each key can map to at most one value.
41   * 
42   * @author Jose Zalacain
43   * @since 1.1
44   */
45  public final class JplMap extends AbstractCompounds implements PrologMap {
46  
47  	private Map<PrologTerm, PrologTerm> map;
48  
49  	JplMap(PrologProvider provider, int size) {
50  		super(PrologTermType.MAP_TYPE, provider);
51  		map = new LinkedHashMap<PrologTerm, PrologTerm>(size);
52  	}
53  
54  	JplMap(PrologProvider provider, Map<? extends PrologTerm, ? extends PrologTerm> m) {
55  		this(provider);
56  		putAll(m);
57  	}
58  
59  	JplMap(PrologProvider provider) {
60  		this(provider, 16);
61  	}
62  
63  	public boolean isList() {
64  		return true;
65  	}
66  
67  	public boolean isStructure() {
68  		return false;
69  	}
70  
71  	public boolean isEmptyList() {
72  		return map.size() == 0;
73  	}
74  
75  	public String getFunctor() {
76  		return ".";
77  	}
78  
79  	public int getArity() {
80  		if (map.size() > 0) {
81  			return 2;
82  		}
83  		return 0;
84  	}
85  
86  	public PrologTerm[] getArguments() {
87  		PrologProvider p = getProvider();
88  		PrologTerm[] args = new PrologTerm[map.size()];
89  		Set<Entry<PrologTerm, PrologTerm>> s = entrySet();
90  		Iterator<Entry<PrologTerm, PrologTerm>> i = s.iterator();
91  		for (int j = 0; j < args.length && i.hasNext(); j++) {
92  			Entry<PrologTerm, PrologTerm> e = i.next();
93  			args[j] = new JplEntry(p, e.getKey(), e.getValue());
94  		}
95  		return args;
96  	}
97  
98  	public PrologTerm getArgument(int index) {
99  		int idx = 0;
100 		PrologTerm term = null;
101 		checkIndex(index, size());
102 		Iterator<PrologTerm> i = iterator();
103 		for (; i.hasNext() && idx <= index; idx++) {
104 			term = i.next();
105 			if (idx == index) {
106 				return term;
107 			}
108 		}
109 		return term;
110 	}
111 
112 	public int hashCode() {
113 		int result = 0;
114 		final int prime = 31;
115 		result = prime * result + ((map == null) ? 0 : map.hashCode());
116 		return result;
117 	}
118 
119 	public boolean equals(Object obj) {
120 		if (this == obj)
121 			return true;
122 		if (obj == null)
123 			return false;
124 		if (getClass() != obj.getClass())
125 			return false;
126 		JplMap other = (JplMap) obj;
127 		if (map == null) {
128 			if (other.map != null)
129 				return false;
130 		} else if (!map.equals(other.map)) {
131 			return false;
132 		}
133 		return true;
134 	}
135 
136 	@Override
137 	public String toString() {
138 		StringBuilder b = new StringBuilder();
139 		Set<Entry<PrologTerm, PrologTerm>> set = entrySet();
140 		Iterator<Entry<PrologTerm, PrologTerm>> i = set.iterator();
141 		b.append('[');
142 		while (i.hasNext()) {
143 			Entry<PrologTerm, PrologTerm> entry = i.next();
144 			b.append(entry.getKey());
145 			b.append('-');
146 			b.append(entry.getValue());
147 			if (i.hasNext()) {
148 				b.append(',');
149 				b.append(' ');
150 			}
151 		}
152 		b.append(']');
153 		return "" + b + "";
154 	}
155 
156 	@Override
157 	public Iterator<PrologTerm> iterator() {
158 		return new PrologMapIterator();
159 	}
160 
161 	@Override
162 	public PrologTerm getHead() {
163 		return iterator().next();
164 	}
165 
166 	@Override
167 	public PrologTerm getTail() {
168 		JplMap m = new JplMap(provider, map);
169 		m.remove(((Entry<?, ?>) getHead()).getKey());
170 		return m;
171 	}
172 
173 	public void putAll(Collection<Entry<PrologTerm, PrologTerm>> entries) {
174 		for (Entry<PrologTerm, PrologTerm> entry : entries) {
175 			put(entry);
176 		}
177 	}
178 
179 	public boolean contains(Entry<PrologTerm, PrologTerm> entry) {
180 		PrologTerm value = get(entry.getKey());
181 		return value != null ? value.equals(entry.getValue()) : false;
182 	}
183 
184 	public void remove(Entry<PrologTerm, PrologTerm> entry) {
185 		remove(entry.getKey());
186 	}
187 
188 	public void put(Entry<PrologTerm, PrologTerm> entry) {
189 		put(entry.getKey(), entry.getValue());
190 	}
191 
192 	private class PrologMapIterator extends AbstractIterator<PrologTerm> implements Iterator<PrologTerm> {
193 
194 		private final Set<PrologTerm> set;
195 		private final Iterator<PrologTerm> itr;
196 
197 		private PrologMapIterator() {
198 			set = new LinkedHashSet<PrologTerm>(map.size());
199 			for (Iterator<Entry<PrologTerm, PrologTerm>> i = map.entrySet().iterator(); i.hasNext();) {
200 				Entry<PrologTerm, PrologTerm> e = i.next();
201 				PrologTerm t = new JplEntry(provider, e.getKey(), e.getValue());
202 				set.add(t);
203 			}
204 			itr = set.iterator();
205 		}
206 
207 		@Override
208 		public boolean hasNext() {
209 			return itr.hasNext();
210 		}
211 
212 		@Override
213 		public PrologTerm next() {
214 			return itr.next();
215 		}
216 
217 	}
218 
219 	public PrologTerm put(PrologTerm key, PrologTerm value) {
220 		return map.put(key, value);
221 	}
222 
223 	public Set<Entry<PrologTerm, PrologTerm>> entrySet() {
224 		return map.entrySet();
225 	}
226 
227 	@Override
228 	public boolean containsKey(Object key) {
229 		return map.containsKey(key);
230 	}
231 
232 	@Override
233 	public boolean containsValue(Object value) {
234 		return map.containsValue(value);
235 	}
236 
237 	@Override
238 	public PrologTerm get(Object key) {
239 		return map.get(key);
240 	}
241 
242 	@Override
243 	public PrologTerm remove(Object key) {
244 		return map.remove(key);
245 	}
246 
247 	@Override
248 	public void putAll(Map<? extends PrologTerm, ? extends PrologTerm> m) {
249 		map.putAll(m);
250 	}
251 
252 	@Override
253 	public Set<PrologTerm> keySet() {
254 		return map.keySet();
255 	}
256 
257 	@Override
258 	public Collection<PrologTerm> values() {
259 		return map.values();
260 	}
261 
262 	@Override
263 	public boolean isEmpty() {
264 		return map.isEmpty();
265 	}
266 
267 	@Override
268 	public void clear() {
269 		map.clear();
270 	}
271 
272 	@Override
273 	public int size() {
274 		return map.size();
275 	}
276 
277 }