View Javadoc
1   /*
2   Copyright (c) 2018 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl.expr;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  import java.util.Random;
22  
23  /**
24   * This class effectively encapsulates the stateful logic of the "Rnd"
25   * function.
26   *
27   * @author James Ahlborn
28   */
29  public class RandomContext
30  {
31    private Source _defRnd;
32    private Map<Integer,Source> _rnds;
33    // default to the value access uses for "last val" when none has been
34    // returned yet
35    private float _lastVal = 1.953125E-02f;
36  
37    public RandomContext()
38    {
39    }
40  
41    public float getRandom(Integer seed) {
42  
43      if(seed == null) {
44        if(_defRnd == null) {
45          _defRnd = new SimpleSource(createRandom(System.currentTimeMillis()));
46        }
47        return _defRnd.get();
48      }
49  
50      if(_rnds == null) {
51        // note, we don't use a SimpleCache here because if we discard a Random
52        // instance, that will cause the values to be reset
53        _rnds = new HashMap<Integer,Source>();
54      }
55  
56      Source rnd = _rnds.get(seed);
57      if(rnd == null) {
58  
59        int seedInt = seed;
60        if(seedInt > 0) {
61          // normal random with a user specified seed
62          rnd = new SimpleSource(createRandom(seedInt));
63        } else if(seedInt < 0) {
64          // returns the same value every time and resets all randoms
65          rnd = new ResetSource(createRandom(seedInt));
66        } else {
67          // returns the last random value returned
68          rnd = new LastValSource();
69        }
70  
71        _rnds.put(seed, rnd);
72      }
73      return rnd.get();
74    }
75  
76    private float setLast(float lastVal) {
77      _lastVal = lastVal;
78      return lastVal;
79    }
80  
81    private void reset() {
82      if(_rnds != null) {
83        _rnds.clear();
84      }
85    }
86  
87    private static Random createRandom(long seed) {
88      // TODO, support SecureRandom?
89      return new Random(seed);
90    }
91  
92    private abstract class Source
93    {
94      public float get() {
95        return setLast(getImpl());
96      }
97  
98      protected abstract float getImpl();
99    }
100 
101   private class SimpleSource extends Source
102   {
103     private final Random _rnd;
104 
105     private SimpleSource(Random rnd) {
106       _rnd = rnd;
107     }
108 
109     @Override
110     protected float getImpl() {
111       return _rnd.nextFloat();
112     }
113   }
114 
115   private class ResetSource extends Source
116   {
117     private final float _val;
118 
119     private ResetSource(Random rnd) {
120       _val = rnd.nextFloat();
121     }
122 
123     @Override
124     protected float getImpl() {
125       reset();
126       return _val;
127     }
128   }
129 
130   private class LastValSource extends Source
131   {
132     private LastValSource() {
133     }
134 
135     @Override
136     protected float getImpl() {
137       return _lastVal;
138     }
139   }
140 }