]> source.dussan.org Git - jackcess.git/commitdiff
move rnd logic to RandomContext
authorJames Ahlborn <jtahlborn@yahoo.com>
Fri, 23 Mar 2018 23:26:35 +0000 (23:26 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Fri, 23 Mar 2018 23:26:35 +0000 (23:26 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/exprs@1144 f203690c-595d-4dc9-a70b-905162fa7fd2

src/main/java/com/healthmarketscience/jackcess/expr/EvalContext.java
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/SimpleCache.java [new file with mode: 0644]
src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultNumberFunctions.java
src/main/java/com/healthmarketscience/jackcess/impl/expr/RandomContext.java [new file with mode: 0644]
src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java

index c140594055662596d55dd10660c299f2c0c457c3..caec4c21e95d391e0320bb9c56213ed8633bdb08 100644 (file)
@@ -36,5 +36,5 @@ public interface EvalContext
   public Value getRowValue(String collectionName, String objName,
                            String colName);
 
-  public Random getRandom(Integer seed);
+  public float getRandom(Integer seed);
 }
index a94d1276078a80a8b3a52d4c42f8582e92ec3d8d..a3b3701de34e014ff3476076ad0e65c65efae605 100644 (file)
@@ -39,7 +39,6 @@ import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -266,13 +265,7 @@ public class DatabaseImpl implements Database
    * MAX_CACHED_LOOKUP_TABLES).
    */
   private final Map<String, TableInfo> _tableLookup =
-    new LinkedHashMap<String, TableInfo>() {
-    private static final long serialVersionUID = 0L;
-    @Override
-    protected boolean removeEldestEntry(Map.Entry<String, TableInfo> e) {
-      return(size() > MAX_CACHED_LOOKUP_TABLES);
-    }
-  };
+    new SimpleCache<String,TableInfo>(MAX_CACHED_LOOKUP_TABLES);
   /** set of table names as stored in the mdb file, created on demand */
   private Set<String> _tableNames;
   /** Reads and writes database pages */
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/SimpleCache.java b/src/main/java/com/healthmarketscience/jackcess/impl/SimpleCache.java
new file mode 100644 (file)
index 0000000..fef2f68
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2018 James Ahlborn
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.healthmarketscience.jackcess.impl;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Simple LRU cache implementation which keeps at most the configured maximum
+ * number of elements.
+ * @author James Ahlborn
+ */
+public class SimpleCache<K,V> extends LinkedHashMap<K,V>
+{
+  private static final long serialVersionUID = 20180313L;  
+
+  private final int _maxSize;
+
+  public SimpleCache(int maxSize) {
+    super(16, 0.75f, true);
+    _maxSize = maxSize;
+  }
+
+  protected int getMaxSize() {
+    return _maxSize;
+  }
+
+  @Override
+  protected boolean removeEldestEntry(Map.Entry<K, V> e) {
+    return(size() > _maxSize);
+  }
+}
index 01952105c52151bb008797e55bc836352d60ec64..0f8ebf2568058369fb13d0418ad9713faba7be21 100644 (file)
@@ -117,7 +117,7 @@ public class DefaultNumberFunctions
     @Override
     protected Value evalVar(EvalContext ctx, Value[] params) {
       Integer seed = ((params.length > 0) ? params[0].getAsLongInt() : null);
-      return BuiltinOperators.toValue(ctx.getRandom(seed).nextFloat());
+      return BuiltinOperators.toValue(ctx.getRandom(seed));
     }
   });
 
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/RandomContext.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/RandomContext.java
new file mode 100644 (file)
index 0000000..b3a21c2
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2018 James Ahlborn
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.healthmarketscience.jackcess.impl.expr;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * This class effectively encapsulates the stateful logic of the "Rnd"
+ * function.
+ *
+ * @author James Ahlborn
+ */
+public class RandomContext 
+{
+  private Source _defRnd;
+  private Map<Integer,Source> _rnds;
+  // default to the value access uses for "last val" when none has been
+  // returned yet
+  private float _lastVal = 1.953125E-02f;
+
+  public RandomContext() 
+  {
+  }
+
+  public float getRandom(Integer seed) {
+
+    if(seed == null) {
+      if(_defRnd == null) {
+        _defRnd = new SimpleSource(createRandom(System.currentTimeMillis()));
+      }
+      return _defRnd.get();
+    }
+
+    if(_rnds == null) {
+      // note, we don't use a SimpleCache here because if we discard a Random
+      // instance, that will cause the values to be reset
+      _rnds = new HashMap<Integer,Source>();
+    }
+
+    Source rnd = _rnds.get(seed);
+    if(rnd == null) {
+
+      int seedInt = seed;
+      if(seedInt > 0) {
+        // normal random with a user specified seed
+        rnd = new SimpleSource(createRandom(seedInt));
+      } else if(seedInt < 0) {
+        // returns the same value every time and resets all randoms
+        rnd = new ResetSource(createRandom(seedInt));
+      } else {
+        // returns the last random value returned
+        rnd = new LastValSource();
+      }
+
+      _rnds.put(seed, rnd);
+    }
+    return rnd.get();
+  }
+
+  private float setLast(float lastVal) {
+    _lastVal = lastVal;
+    return lastVal;
+  }
+
+  private void reset() {
+    if(_rnds != null) {
+      _rnds.clear();
+    }
+  }
+
+  private static Random createRandom(long seed) {
+    // FIXME, support SecureRandom?
+    return new Random(seed);
+  }
+
+  private abstract class Source
+  {
+    public float get() {
+      return setLast(getImpl());
+    }
+
+    protected abstract float getImpl();
+  }
+
+  private class SimpleSource extends Source
+  {
+    private final Random _rnd;
+
+    private SimpleSource(Random rnd) {
+      _rnd = rnd;
+    }
+
+    @Override
+    protected float getImpl() {
+      return _rnd.nextFloat();
+    }
+  }
+
+  private class ResetSource extends Source
+  {
+    private final float _val;
+
+    private ResetSource(Random rnd) {
+      _val = rnd.nextFloat();
+    }
+
+    @Override
+    protected float getImpl() {
+      reset();
+      return _val;
+    }
+  }
+
+  private class LastValSource extends Source
+  {
+    private LastValSource() {
+    }
+
+    @Override
+    protected float getImpl() {
+      return _lastVal;
+    }
+  }
+}
index c6bda5b6206644cf14072e3c5772b0de57404a8b..a3eb46a2b0acecb4e18273a1a3ba28f0707a349a 100644 (file)
@@ -19,7 +19,6 @@ package com.healthmarketscience.jackcess.impl.expr;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import java.util.Random;
 
 import com.healthmarketscience.jackcess.DatabaseBuilder;
 import com.healthmarketscience.jackcess.TestUtil;
@@ -382,9 +381,7 @@ public class ExpressionatorTest extends TestCase
   private static final class TestEvalContext implements EvalContext
   {
     private final Value _thisVal;
-    private Random _defRnd;
-    private Random _rnd;
-    private long _rndSeed;
+    private final RandomContext _rndCtx = new RandomContext();
 
     private TestEvalContext(Value thisVal) {
       _thisVal = thisVal;
@@ -416,18 +413,8 @@ public class ExpressionatorTest extends TestCase
       throw new UnsupportedOperationException();
     }
 
-    public Random getRandom(Integer seed) {
-      if(seed == null) {
-        if(_defRnd == null) {
-          _defRnd = new Random(System.currentTimeMillis());
-        }
-        return _defRnd;
-      }
-      if((_rnd == null) || (seed != _rndSeed)) {
-        _rndSeed = seed;
-        _rnd = new Random(_rndSeed);
-      }
-      return _rnd;
+    public float getRandom(Integer seed) {
+      return _rndCtx.getRandom(seed);
     } 
   }
 }