From 61e851b05b1b6ef968f363bf50072abb2190ef74 Mon Sep 17 00:00:00 2001 From: AlexisDrogoul Date: Sun, 16 May 2021 19:06:52 +0700 Subject: [PATCH] Addition of an "init/copy" mechanism in object pools --- .../msi/gama/common/geometry/Envelope3D.java | 92 ++++++++----------- .../src/msi/gama/common/util/PoolUtils.java | 62 ++++++++++--- .../gama/runtime/AgentExecutionContext.java | 2 +- .../msi/gama/runtime/ExecutionContext.java | 18 ++-- .../src/msi/gama/util/Collector.java | 69 +++++++------- .../src/msi/gama/util/ICollector.java | 2 + 6 files changed, 129 insertions(+), 116 deletions(-) diff --git a/msi.gama.core/src/msi/gama/common/geometry/Envelope3D.java b/msi.gama.core/src/msi/gama/common/geometry/Envelope3D.java index d61cfdf8d9..36a7a33e12 100644 --- a/msi.gama.core/src/msi/gama/common/geometry/Envelope3D.java +++ b/msi.gama.core/src/msi/gama/common/geometry/Envelope3D.java @@ -38,7 +38,7 @@ public class Envelope3D extends Envelope implements IDisposable { private final static PoolUtils.ObjectPool POOL = - PoolUtils.create("Envelope 3D", true, () -> new Envelope3D(), null); + PoolUtils.create("Envelope 3D", true, () -> new Envelope3D(), (from, to) -> to.set(from), null); public static final Envelope3D EMPTY = create(); @@ -47,14 +47,14 @@ public static Envelope3D create() { } public static Envelope3D of(final Geometry g) { - if (g instanceof GeometryCollection) { return of((GeometryCollection) g); } + if (g instanceof GeometryCollection) return of((GeometryCollection) g); final ICoordinates sq = GeometryUtils.getContourCoordinates(g); return sq.getEnvelope(); } public static Envelope3D of(final GeometryCollection g) { final int i = g.getNumGeometries(); - if (i == 0) { return EMPTY; } + if (i == 0) return EMPTY; final Envelope3D result = of(g.getGeometryN(0)); for (int j = 1; j < i; j++) { result.expandToInclude(of(g.getGeometryN(j))); @@ -190,6 +190,11 @@ public void init(final Envelope3D env) { this.maxz = env.maxz; } + private Envelope3D set(final Envelope3D env) { + init(env); + return this; + } + /** * Makes this Envelope a "null" envelope, that is, the envelope of the empty geometry. */ @@ -206,7 +211,7 @@ public void setToNull() { * @return max z - min z, or 0 if this is a null Envelope */ public double getDepth() { - if (isNull()) { return 0; } + if (isNull()) return 0; return maxz - minz; } @@ -237,7 +242,7 @@ public double getMaxZ() { * @return 0.0 if the envelope is null */ public double getVolume() { - if (isNull()) { return 0.0; } + if (isNull()) return 0.0; return getWidth() * getHeight() * getDepth(); } @@ -248,7 +253,7 @@ public double getVolume() { */ @Override public double minExtent() { - if (isNull()) { return 0.0; } + if (isNull()) return 0.0; return Math.min(getWidth(), Math.min(getHeight(), getDepth())); } @@ -259,7 +264,7 @@ public double minExtent() { */ @Override public double maxExtent() { - if (isNull()) { return 0.0; } + if (isNull()) return 0.0; return Math.max(getWidth(), Math.max(getHeight(), getDepth())); } @@ -295,15 +300,13 @@ public void expandBy(final double distance) { * the distance to expand the envelope along the the Y axis */ public void expandBy(final double deltaX, final double deltaY, final double deltaZ) { - if (isNull()) { return; } + if (isNull()) return; minz -= deltaZ; maxz += deltaZ; expandBy(deltaX, deltaY); // check for envelope disappearing - if (minz > maxz) { - setToNull(); - } + if (minz > maxz) { setToNull(); } } /** @@ -324,12 +327,8 @@ public void expandToInclude(final double x, final double y, final double z) { maxz = z; } else { expandToInclude(x, y); - if (z < minz) { - minz = z; - } - if (z > maxz) { - maxz = z; - } + if (z < minz) { minz = z; } + if (z > maxz) { maxz = z; } } } @@ -344,7 +343,7 @@ public void expandToInclude(final double x, final double y, final double z) { * the amount to translate along the Z axis */ public Envelope3D translate(final double transX, final double transY, final double transZ) { - if (isNull()) { return this; } + if (isNull()) return this; init(getMinX() + transX, getMaxX() + transX, getMinY() + transY, getMaxY() + transY, getMinZ() + transZ, getMaxZ() + transZ); return this; @@ -357,7 +356,7 @@ public Envelope3D translate(final double transX, final double transY, final doub */ @Override public GamaPoint centre() { - if (isNull()) { return null; } + if (isNull()) return null; return new GamaPoint((getMinX() + getMaxX()) / 2.0, (getMinY() + getMaxY()) / 2.0, (getMinZ() + getMaxZ()) / 2.0); } @@ -371,7 +370,7 @@ public GamaPoint centre() { */ @Override public boolean intersects(final Envelope other) { - if (!super.intersects(other)) { return false; } + if (!super.intersects(other)) return false; return !(getMinZOf(other) > maxz || getMaxZOf(other) < minz); } @@ -399,7 +398,7 @@ public boolean intersects(final Coordinate p) { * @return true if the point overlaps this Envelope */ protected boolean intersects(final double x, final double y, final double z) { - if (isNull()) { return false; } + if (isNull()) return false; return intersects(x, y) && !(z < minz || z > maxz); } @@ -414,7 +413,7 @@ protected boolean intersects(final double x, final double y, final double z) { * Envelope. */ protected boolean covers(final double x, final double y, final double z) { - if (isNull()) { return false; } + if (isNull()) return false; return covers(x, y) && z >= minz && z <= maxz; } @@ -440,8 +439,8 @@ public boolean covers(final Coordinate p) { */ @Override public boolean covers(final Envelope other) { - if (isNull() || other.isNull()) { return false; } - if (!super.covers(other)) { return false; } + if (isNull() || other.isNull()) return false; + if (!super.covers(other)) return false; return getMinZOf(other) >= minz && getMaxZOf(other) <= maxz; } @@ -451,36 +450,30 @@ public boolean covers(final Envelope other) { */ @Override public double distance(final Envelope env) { - if (intersects(env)) { return 0; } + if (intersects(env)) return 0; double dx = 0.0; if (getMaxX() < env.getMinX()) { dx = env.getMinX() - getMaxX(); - } else if (getMinX() > env.getMaxX()) { - dx = getMinX() - env.getMaxX(); - } + } else if (getMinX() > env.getMaxX()) { dx = getMinX() - env.getMaxX(); } double dy = 0.0; if (getMaxY() < env.getMinY()) { dy = env.getMinY() - getMaxY(); - } else if (getMinY() > env.getMaxY()) { - dy = getMinY() - env.getMaxY(); - } + } else if (getMinY() > env.getMaxY()) { dy = getMinY() - env.getMaxY(); } double dz = 0.0; final double otherMinZ = getMinZOf(env); final double otherMaxZ = getMaxZOf(env); if (maxz < otherMinZ) { dz = otherMinZ - maxz; - } else if (minz > otherMaxZ) { - dz = minz - otherMaxZ; - } + } else if (minz > otherMaxZ) { dz = minz - otherMaxZ; } // if either is zero, the envelopes overlap either vertically or // horizontally - if (dx == 0.0 && dz == 0.0) { return dy; } - if (dy == 0.0 && dz == 0.0) { return dx; } - if (dx == 0.0 && dy == 0.0) { return dz; } + if (dx == 0.0 && dz == 0.0) return dy; + if (dy == 0.0 && dz == 0.0) return dx; + if (dx == 0.0 && dy == 0.0) return dz; return Math.sqrt(dx * dx + dy * dy + dz * dz); } @@ -500,7 +493,7 @@ private Envelope3D() { */ @Override public Envelope3D intersection(final Envelope env) { - if (isNull() || env.isNull() || !intersects(env)) { return EMPTY; } + if (isNull() || env.isNull() || !intersects(env)) return EMPTY; final Envelope xyInt = super.intersection(env); final double otherMinZ = getMinZOf(env); final double intMinZ = minz > otherMinZ ? minz : otherMinZ; @@ -518,7 +511,7 @@ public Envelope3D intersection(final Envelope env) { */ @Override public void expandToInclude(final Envelope other) { - if (other.isNull()) { return; } + if (other.isNull()) return; final double otherMinZ = getMinZOf(other); final double otherMaxZ = getMaxZOf(other); if (isNull()) { @@ -527,12 +520,8 @@ public void expandToInclude(final Envelope other) { maxz = otherMaxZ; } else { super.expandToInclude(other); - if (otherMinZ < minz) { - minz = otherMinZ; - } - if (otherMaxZ > maxz) { - maxz = otherMaxZ; - } + if (otherMinZ < minz) { minz = otherMinZ; } + if (otherMaxZ > maxz) { maxz = otherMaxZ; } } } @@ -541,7 +530,7 @@ public void expandToInclude(final Envelope other) { * @return */ private double getMaxZOf(final Envelope other) { - if (other instanceof Envelope3D) { return ((Envelope3D) other).maxz; } + if (other instanceof Envelope3D) return ((Envelope3D) other).maxz; return 0d; } @@ -550,7 +539,7 @@ private double getMaxZOf(final Envelope other) { * @return */ private double getMinZOf(final Envelope other) { - if (other instanceof Envelope3D) { return ((Envelope3D) other).minz; } + if (other instanceof Envelope3D) return ((Envelope3D) other).minz; return 0d; } @@ -572,9 +561,9 @@ public int hashCode() { */ @Override public boolean equals(final Object other) { - if (!(other instanceof Envelope3D)) { return false; } + if (!(other instanceof Envelope3D)) return false; final Envelope3D otherEnvelope = (Envelope3D) other; - if (isNull()) { return otherEnvelope.isNull(); } + if (isNull()) return otherEnvelope.isNull(); return super.equals(other) && Comparison.equal(minz, otherEnvelope.getMinZ()) && Comparison.equal(maxz, otherEnvelope.getMaxZ()); } @@ -588,9 +577,8 @@ public boolean isHorizontal() { } public Polygon toGeometry() { - if (isFlat()) { + if (isFlat()) return (Polygon) GamaGeometryType.buildRectangle(getWidth(), getHeight(), centre()).getInnerGeometry(); - } return (Polygon) GamaGeometryType.buildBox(getWidth(), getHeight(), getDepth(), centre()).getInnerGeometry(); } @@ -605,7 +593,7 @@ public Envelope3D yNegated() { } public Envelope3D rotate(final AxisAngle rotation) { - if (isNull()) { return this; } + if (isNull()) return this; GamaShape se = new GamaShape(this); se = new GamaShape(se, null, rotation, se.getLocation()); init(se.getEnvelope()); diff --git a/msi.gama.core/src/msi/gama/common/util/PoolUtils.java b/msi.gama.core/src/msi/gama/common/util/PoolUtils.java index 5aae915fb4..c31a335760 100644 --- a/msi.gama.core/src/msi/gama/common/util/PoolUtils.java +++ b/msi.gama.core/src/msi/gama/common/util/PoolUtils.java @@ -23,11 +23,12 @@ public class PoolUtils { } public static void WriteStats() { - if (!DEBUG.IS_ON()) { return; } + if (!DEBUG.IS_ON()) return; DEBUG.SECTION("Pool statistics"); POOLS.forEach((p) -> { - DEBUG.OUT(p.name, 30, "accessed " + p.accessed + " times | created " + p.created + " times | released " - + p.released + " times | objects size: " + p.objects.size()); + long percentage = p.accessed == 0 ? 100 : 100 - (long) (p.created * 100d / p.accessed); + DEBUG.OUT(p.name, 30, "instances created " + p.created + " / instances asked " + p.accessed + " = " + + percentage + "% of coverage"); }); } @@ -35,6 +36,11 @@ public interface ObjectFactory { T createNew(); } + public interface ObjectCopy { + + void createNew(T copyFrom, T copyTo); + } + public interface ObjectCleaner { void clean(T object); } @@ -44,18 +50,20 @@ public static class ObjectPool implements IDisposable { private String name; private long accessed, released, created; private final ObjectFactory factory; + private final ObjectCopy copy; private final ObjectCleaner cleaner; private final Queue objects; public boolean active; - private ObjectPool(final ObjectFactory factory, final ObjectCleaner cleaner) { + private ObjectPool(final ObjectFactory factory, final ObjectCopy copy, final ObjectCleaner cleaner) { this.factory = factory; + this.copy = copy; this.cleaner = cleaner; objects = Queues.synchronizedDeque(Queues.newArrayDeque()); } public T get() { - if (!POOL || !active) { return factory.createNew(); } + if (!POOL || !active) return factory.createNew(); accessed++; T result = objects.poll(); @@ -66,14 +74,20 @@ public T get() { return result; } - public void release(final T t) { - if (t == null) { return; } - if (cleaner != null) { - cleaner.clean(t); - } - if (POOL && active) { - released++; - objects.offer(t); + public T get(final T from) { + T result = get(); + if (copy != null) { copy.createNew(from, result); } + return result; + } + + public void release(final T... tt) { + if (tt == null) return; + for (T t : tt) { + if (cleaner != null) { cleaner.clean(t); } + if (POOL && active) { + released++; + objects.offer(t); + } } } @@ -84,10 +98,28 @@ public void dispose() { } } + /** + * Creates a new object pool + * + * @param + * the type of objects created and maintained in the poool + * @param name + * the name of the pool + * @param active + * whether or not it is active + * @param factory + * the factory to create new objects + * @param copy + * the factory to create new objects from existing ones + * @param cleaner + * the code to execute to return the object to its pristine state + * @return + */ + public static ObjectPool create(final String name, final boolean active, final ObjectFactory factory, - final ObjectCleaner cleaner) { + final ObjectCopy copy, final ObjectCleaner cleaner) { DEBUG.OUT("Adding object pool: " + name); - final ObjectPool result = new ObjectPool<>(factory, cleaner); + final ObjectPool result = new ObjectPool<>(factory, copy, cleaner); result.active = active; result.name = name; // if (DEBUG.IS_ON()) { diff --git a/msi.gama.core/src/msi/gama/runtime/AgentExecutionContext.java b/msi.gama.core/src/msi/gama/runtime/AgentExecutionContext.java index f042730697..ec94815857 100644 --- a/msi.gama.core/src/msi/gama/runtime/AgentExecutionContext.java +++ b/msi.gama.core/src/msi/gama/runtime/AgentExecutionContext.java @@ -7,7 +7,7 @@ class AgentExecutionContext implements IDisposable { private static final PoolUtils.ObjectPool POOL = - PoolUtils.create("Agent Execution Context", true, () -> new AgentExecutionContext(), null); + PoolUtils.create("Agent Execution Context", true, () -> new AgentExecutionContext(), null, null); public static AgentExecutionContext create(final IAgent agent, final AgentExecutionContext outer) { final AgentExecutionContext result = POOL.get(); diff --git a/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java b/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java index 690fd0bd6e..04431dd392 100644 --- a/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java +++ b/msi.gama.core/src/msi/gama/runtime/ExecutionContext.java @@ -20,7 +20,7 @@ public class ExecutionContext implements IExecutionContext { private static final PoolUtils.ObjectPool POOL = - PoolUtils.create("Execution Context", true, () -> new ExecutionContext(), null); + PoolUtils.create("Execution Context", true, () -> new ExecutionContext(), null, null); public static ExecutionContext create(final IExecutionContext outer) { return create(outer.getScope(), outer); @@ -64,9 +64,7 @@ public final IExecutionContext getOuterContext() { @Override public void setTempVar(final String name, final Object value) { if (local == null || !local.containsKey(name)) { - if (outer != null) { - outer.setTempVar(name, value); - } + if (outer != null) { outer.setTempVar(name, value); } } else { local.put(name, value); } @@ -75,7 +73,7 @@ public void setTempVar(final String name, final Object value) { @Override public Object getTempVar(final String name) { - if (local == null || !local.containsKey(name)) { return outer == null ? null : outer.getTempVar(name); } + if (local == null || !local.containsKey(name)) return outer == null ? null : outer.getTempVar(name); return local.get(name); } @@ -106,27 +104,25 @@ public void clearLocalVars() { @Override public void putLocalVar(final String varName, final Object val) { - if (local == null) { - local = GamaMapFactory.createUnordered(); - } + if (local == null) { local = GamaMapFactory.createUnordered(); } local.put(varName, val); } @Override public Object getLocalVar(final String string) { - if (local == null) { return null; } + if (local == null) return null; return local.get(string); } @Override public boolean hasLocalVar(final String name) { - if (local == null) { return false; } + if (local == null) return false; return local.containsKey(name); } @Override public void removeLocalVar(final String name) { - if (local == null) { return; } + if (local == null) return; local.remove(name); } diff --git a/msi.gama.core/src/msi/gama/util/Collector.java b/msi.gama.core/src/msi/gama/util/Collector.java index 0df8f15d28..2f37df1964 100644 --- a/msi.gama.core/src/msi/gama/util/Collector.java +++ b/msi.gama.core/src/msi/gama/util/Collector.java @@ -36,14 +36,15 @@ public abstract class Collector> implements ICollector, Collection { - private static final PoolUtils.ObjectPool> LISTS = - PoolUtils.create("Ordered Collectors", true, () -> new Collector.AsList<>(), c -> c.clear()); + private static final PoolUtils.ObjectPool> LISTS = PoolUtils.create("Ordered Collectors", true, + () -> new Collector.AsList<>(), (from, to) -> to.set(from), c -> c.clear()); - private static final PoolUtils.ObjectPool> SETS = - PoolUtils.create("Unique Collectors", true, () -> new Collector.AsSet<>(), c -> c.clear()); + private static final PoolUtils.ObjectPool> SETS = PoolUtils.create("Unique Collectors", true, + () -> new Collector.AsSet<>(), (from, to) -> to.set(from), c -> c.clear()); private static final PoolUtils.ObjectPool> ORDERED_SETS = - PoolUtils.create("Unique Ordered Collectors", true, () -> new Collector.AsOrderedSet<>(), c -> c.clear()); + PoolUtils.create("Unique Ordered Collectors", true, () -> new Collector.AsOrderedSet<>(), + (from, to) -> to.set(from), c -> c.clear()); @SuppressWarnings ("unchecked") public static final Collector.AsList getList() { @@ -65,32 +66,36 @@ public static final void release(final ICollector coll) { LISTS.release(coll); } else if (coll instanceof AsOrderedSet) { ORDERED_SETS.release(coll); - } else if (coll instanceof AsSet) { - SETS.release(coll); - } + } else if (coll instanceof AsSet) { SETS.release(coll); } + } + + @SuppressWarnings ("unchecked") + @Override + public void set(final ICollector c) { + this.addAll((Collection) c.items()); } @Override public boolean removeIf(final Predicate filter) { - if (collect != null) { return collect.removeIf(filter); } + if (collect != null) return collect.removeIf(filter); return ICollector.super.removeIf(filter); } @Override public Spliterator spliterator() { - if (collect != null) { return collect.spliterator(); } + if (collect != null) return collect.spliterator(); return ICollector.super.spliterator(); } @Override public Stream stream() { - if (collect != null) { return collect.stream(); } + if (collect != null) return collect.stream(); return ICollector.super.stream(); } @Override public Stream parallelStream() { - if (collect != null) { return collect.parallelStream(); } + if (collect != null) return collect.parallelStream(); return ICollector.super.parallelStream(); } @@ -101,29 +106,25 @@ protected AsSet() {} public static class Concurrent extends AsSet { @Override protected void initCollect() { - if (collect == null) { - collect = Sets.newConcurrentHashSet(); - } + if (collect == null) { collect = Sets.newConcurrentHashSet(); } } @Override public boolean remove(final Object o) { - if (o == null) { return false; } + if (o == null) return false; return super.remove(o); } @Override public boolean removeAll(final Collection o) { - if (o == null) { return false; } + if (o == null) return false; return super.removeAll(o); } } @Override protected void initCollect() { - if (collect == null) { - collect = new HashSet<>(); - } + if (collect == null) { collect = new HashSet<>(); } } @Override @@ -139,9 +140,7 @@ protected AsList() {} @Override protected void initCollect() { - if (collect == null) { - collect = GamaListFactory.create(); - } + if (collect == null) { collect = GamaListFactory.create(); } } @Override @@ -150,9 +149,7 @@ public IList items() { } public void setSize(final int size) { - if (size > 0 && collect == null) { - collect = GamaListFactory.create(Types.NO_TYPE, size); - } + if (size > 0 && collect == null) { collect = GamaListFactory.create(Types.NO_TYPE, size); } } @@ -168,40 +165,38 @@ protected AsOrderedSet() {} @Override protected void initCollect() { - if (collect == null) { - collect = new LinkedHashSet<>(); - } + if (collect == null) { collect = new LinkedHashSet<>(); } } } @Override public int size() { - if (collect == null) { return 0; } + if (collect == null) return 0; return collect.size(); } @Override public boolean contains(final Object o) { - if (collect == null) { return false; } + if (collect == null) return false; return collect.contains(o); } @Override public Object[] toArray() { - if (collect == null) { return new Object[0]; } + if (collect == null) return new Object[0]; return collect.toArray(); } @Override public T[] toArray(final T[] a) { - if (collect == null) { return a; } + if (collect == null) return a; return collect.toArray(a); } @Override public boolean containsAll(final Collection c) { - if (collect == null) { return false; } + if (collect == null) return false; return collect.containsAll(c); } @@ -213,13 +208,13 @@ public boolean addAll(final Collection c) { @Override public boolean removeAll(final Collection c) { - if (collect == null) { return false; } + if (collect == null) return false; return collect.removeAll(c); } @Override public boolean retainAll(final Collection c) { - if (collect == null) { return false; } + if (collect == null) return false; return collect.retainAll(c); } @@ -258,7 +253,7 @@ public Iterator iterator() { */ @Override public boolean remove(final Object e) { - if (collect == null) { return false; } + if (collect == null) return false; return collect.remove(e); } diff --git a/msi.gama.core/src/msi/gama/util/ICollector.java b/msi.gama.core/src/msi/gama/util/ICollector.java index 78cec81ae9..7d6d3853bf 100644 --- a/msi.gama.core/src/msi/gama/util/ICollector.java +++ b/msi.gama.core/src/msi/gama/util/ICollector.java @@ -28,4 +28,6 @@ default void shuffleInPlaceWith(final RandomUtils random) { random.shuffleInPlace(items()); } + void set(final ICollector c); + } \ No newline at end of file