SimpleEnvironment.java 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright (c) 1996-2000, 2001, 2002, 2004 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.mapping;
  4. import java.io.*;
  5. /** Concrete implementation of <code>Environment</code>.
  6. * (Should consider merging this code with Table2D.)
  7. */
  8. public class SimpleEnvironment extends Environment
  9. {
  10. NamedLocation[] table;
  11. int log2Size;
  12. private int mask;
  13. /** Doesn't count inherited bindings. */
  14. int num_bindings;
  15. int currentTimestamp;
  16. /** Size does not include inherited Locations. */
  17. public int size () { return num_bindings; }
  18. public static Location getCurrentLocation (String name)
  19. {
  20. return getCurrent().getLocation(name, true);
  21. }
  22. public static Object lookup_global (Symbol name)
  23. throws UnboundLocationException
  24. {
  25. Location binding = getCurrent().lookup(name);
  26. if (binding == null)
  27. throw new UnboundLocationException(name);
  28. return binding.get();
  29. }
  30. /** A special "end-of-list" value added for the sake of getEnvironment. */
  31. NamedLocation sharedTail;
  32. public SimpleEnvironment ()
  33. {
  34. this(64);
  35. }
  36. public SimpleEnvironment (String name)
  37. {
  38. this();
  39. setName(name);
  40. }
  41. public SimpleEnvironment (int capacity)
  42. {
  43. log2Size = 4;
  44. while (capacity > (1 << log2Size))
  45. log2Size++;
  46. capacity = 1 << log2Size;
  47. table = new NamedLocation[capacity];
  48. mask = capacity - 1;
  49. sharedTail = new PlainLocation(null, null, this);
  50. }
  51. public NamedLocation lookup (Symbol name, Object property, int hash)
  52. {
  53. return lookupDirect(name, property, hash);
  54. }
  55. public NamedLocation lookupDirect (Symbol name, Object property, int hash)
  56. {
  57. int index = hash & this.mask;
  58. for (NamedLocation loc = table[index];
  59. loc != null; loc = loc.next)
  60. {
  61. if (loc.matches(name, property))
  62. return loc;
  63. }
  64. return null;
  65. }
  66. public synchronized NamedLocation
  67. getLocation (Symbol name, Object property, int hash, boolean create)
  68. {
  69. NamedLocation loc = lookup(name, property, hash);
  70. if (loc != null)
  71. return loc;
  72. if (! create)
  73. return null;
  74. return addUnboundLocation(name, property, hash);
  75. }
  76. protected NamedLocation addUnboundLocation(Symbol name, Object property,
  77. int hash)
  78. {
  79. int index = hash & mask;
  80. NamedLocation loc = newEntry(name, property, index);
  81. loc.base = null;
  82. loc.value = Location.UNBOUND;
  83. return loc;
  84. }
  85. public void put(Symbol key, Object property, Object newValue)
  86. {
  87. boolean create = (flags & CAN_IMPLICITLY_DEFINE) != 0;
  88. Location loc = getLocation(key, property, create);
  89. if (loc == null)
  90. throw new UnboundLocationException(key);
  91. else if (loc.isConstant())
  92. throw new IllegalStateException("attempt to modify read-only location: "
  93. + key + " in "+this+" loc:"+loc);
  94. loc.set(newValue);
  95. }
  96. // Rename to newEntry? FIXME
  97. protected NamedLocation newLocation (Symbol name, Object property)
  98. {
  99. if ((flags & THREAD_SAFE) != 0)
  100. return new SharedLocation(name, property, currentTimestamp);
  101. else
  102. return new PlainLocation(name, property);
  103. }
  104. NamedLocation newEntry (Symbol name, Object property, int index)
  105. {
  106. NamedLocation loc = newLocation(name, property);
  107. NamedLocation first = table[index];
  108. loc.next = first == null ? sharedTail : first;
  109. table[index] = loc;
  110. num_bindings++;
  111. if (num_bindings >= table.length)
  112. rehash();
  113. return loc;
  114. }
  115. public NamedLocation define (Symbol sym, Object property, int hash,
  116. Object newValue)
  117. {
  118. int index = hash & mask;
  119. NamedLocation first = table[index];
  120. NamedLocation loc = first;
  121. for (;;)
  122. {
  123. if (loc == null)
  124. {
  125. // FIXME increment numBindings?
  126. loc = newEntry(sym, property, index);
  127. loc.set(newValue);
  128. return loc;
  129. }
  130. else if (loc.matches(sym, property))
  131. {
  132. if (! (loc.isBound() ? getCanDefine() : getCanRedefine()))
  133. redefineError(sym, property, loc);
  134. loc.base = null;
  135. loc.value = newValue;
  136. return loc;
  137. }
  138. loc = loc.next;
  139. }
  140. }
  141. public void define (Symbol sym, Object property, Object newValue)
  142. {
  143. int hash = sym.hashCode() ^ System.identityHashCode(property);
  144. define(sym, property, hash, newValue);
  145. }
  146. protected void redefineError (Symbol name, Object property, Location loc)
  147. {
  148. throw new IllegalStateException("prohibited define/redefine of "
  149. +name+" in "+this);
  150. }
  151. public NamedLocation addLocation (Symbol name, Object property, Location loc)
  152. {
  153. return addLocation(name, property,
  154. name.hashCode() ^ System.identityHashCode(property), loc);
  155. }
  156. // FIXME rename to define
  157. NamedLocation addLocation (Symbol name, Object property, int hash, Location loc)
  158. {
  159. if (loc instanceof DynamicLocation
  160. && ((DynamicLocation) loc).property == property)
  161. loc = ((DynamicLocation) loc).getLocation();
  162. NamedLocation nloc = lookupDirect(name, property, hash);
  163. if (loc == nloc)
  164. return nloc;
  165. boolean bound = (nloc != null);
  166. if (! bound)
  167. nloc = addUnboundLocation(name, property, hash);
  168. if ((flags & CAN_DEFINE+CAN_REDEFINE) != CAN_DEFINE+CAN_REDEFINE)
  169. {
  170. if (bound)
  171. bound = nloc.isBound();
  172. // We do this redundant testing to avoid invoking isBound,
  173. // which may be expensive and/or cause needless errors, such in the
  174. // case of a lazy ClassMemberLocation referring to a missing class.
  175. if (bound
  176. ? ((flags & CAN_REDEFINE) == 0)
  177. : ((flags & CAN_DEFINE) == 0) && loc.isBound())
  178. redefineError(name, property, nloc);
  179. }
  180. if ((flags & Environment.INDIRECT_DEFINES) != 0)
  181. nloc.base = ((SimpleEnvironment) ((InheritingEnvironment) this).getParent(0)).addLocation(name, property, hash, loc);
  182. else
  183. nloc.base = loc;
  184. nloc.value = IndirectableLocation.INDIRECT_FLUIDS;
  185. return nloc;
  186. }
  187. void rehash ()
  188. {
  189. NamedLocation[] oldTable = table;
  190. int oldCapacity = oldTable.length;
  191. int newCapacity = 2 * oldCapacity;
  192. NamedLocation[] newTable = new NamedLocation[newCapacity];
  193. int newMask = newCapacity - 1;
  194. for (int i = oldCapacity; --i >= 0;)
  195. {
  196. for (NamedLocation element = oldTable[i];
  197. element != null && element != sharedTail; )
  198. {
  199. NamedLocation next = element.next;
  200. Symbol name = element.name;
  201. Object property = element.property;
  202. int hash = name.hashCode() ^ System.identityHashCode(property);
  203. int j = hash & newMask;
  204. NamedLocation head = newTable[j];
  205. if (head == null)
  206. head = sharedTail;
  207. element.next = head;
  208. newTable[j] = element;
  209. element = next;
  210. }
  211. }
  212. table = newTable;
  213. log2Size++;
  214. mask = newMask;
  215. }
  216. public Location unlink (Symbol symbol, Object property, int hash)
  217. {
  218. int index = hash & this.mask;
  219. NamedLocation prev = null;
  220. NamedLocation loc = table[index];
  221. while (loc != null)
  222. {
  223. NamedLocation next = loc.next;
  224. if (loc.matches(symbol, property))
  225. {
  226. if (! getCanRedefine())
  227. redefineError(symbol, property, loc);
  228. if (prev == null)
  229. table[index] = next;
  230. else
  231. prev.next = loc;
  232. num_bindings--;
  233. return loc;
  234. }
  235. prev = loc;
  236. loc = next;
  237. }
  238. return null;
  239. }
  240. /** Does not enumerate inherited Locations. */
  241. public LocationEnumeration enumerateLocations()
  242. {
  243. LocationEnumeration it = new LocationEnumeration(table, 1 << log2Size);
  244. it.env = this;
  245. return it;
  246. }
  247. /** Does enumerate inherited Locations. */
  248. public LocationEnumeration enumerateAllLocations()
  249. {
  250. return enumerateLocations();
  251. }
  252. protected boolean hasMoreElements (LocationEnumeration it)
  253. {
  254. for (;;)
  255. {
  256. if (it.nextLoc == null)
  257. {
  258. it.prevLoc = null;
  259. if (--it.index < 0)
  260. return false;
  261. it.nextLoc = it.bindings[it.index];
  262. if (it.nextLoc == null)
  263. continue;
  264. }
  265. if (it.nextLoc.name == null)
  266. it.nextLoc = it.nextLoc.next;
  267. else
  268. break;
  269. }
  270. return true;
  271. }
  272. public void writeExternal(ObjectOutput out) throws IOException
  273. {
  274. out.writeObject(getSymbol());
  275. }
  276. public void readExternal(ObjectInput in)
  277. throws IOException, ClassNotFoundException
  278. {
  279. setSymbol(in.readObject());
  280. }
  281. public Object readResolve() throws ObjectStreamException
  282. {
  283. String name = getName();
  284. Environment env = (Environment) envTable.get(name);
  285. if (env != null)
  286. return env;
  287. envTable.put(name, this);
  288. return this;
  289. }
  290. /* #ifdef JAVA2 */
  291. public java.util.Set entrySet ()
  292. {
  293. return new EnvironmentMappings(this);
  294. }
  295. /* #endif */
  296. public String toStringVerbose ()
  297. {
  298. StringBuffer sbuf = new StringBuffer();
  299. toStringBase(sbuf);
  300. return "#<environment "+getName()+" num:"+num_bindings
  301. +" ts:"+currentTimestamp+sbuf+'>';
  302. }
  303. protected void toStringBase (StringBuffer sbuf) { ; }
  304. }
  305. /* #ifdef JAVA2 */
  306. class EnvironmentMappings
  307. extends java.util.AbstractSet /* <Location> */
  308. {
  309. SimpleEnvironment env;
  310. public EnvironmentMappings (SimpleEnvironment env) { this.env = env; }
  311. public int size() { return env.size(); }
  312. public java.util.Iterator iterator ()
  313. {
  314. return new LocationEnumeration(env);
  315. }
  316. }
  317. /* #endif */