Java tutorial
/* * Licensed to the Ted Dunning under one or more contributor license * agreements. See the NOTICE file that may be * distributed with this work for additional information * regarding copyright ownership. Ted Dunning licenses this file * to you 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.mapr.synth; import com.google.common.base.Charsets; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import java.util.Iterator; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; /** * Defines a tree of random number generators such that complex randomized structures can be * built in parallel in a deterministic way. The based idea is that a NestedRandom can produce * off-shoot NestedRandom generators given either an index or a String. You can also get a * conventional Random from a NestedRandom at any time. The idea is that a data structure * can have components which need stable randomness sources and those components will also have * components. At the leaves of such a JSON-style nested data structure, you have conventional * random number generators seeded consistently given the path down to that generator. * * Note that NestedRandom instances are immutable and do not share any storage. They are * fully thread safe. */ public class NestedRandom implements Iterable<NestedRandom> { private NestedRandom parent; private final String content; private int seed; /** * Returns a NestedRandom with a default seed. */ public NestedRandom() { this(0); } /** * Returns a NestedRandom with a specified seed. * @param seed The seed to use. */ public NestedRandom(int seed) { this(null, seed); } /** * Get a NestedRandom corresponding to the component with the specified name. * @param component Which component to return. * @return A component stream. */ public NestedRandom get(String component) { return new NestedRandom(this, component); } /** * Get a NestedRandom corresponding to a specified position in the notional array * of random generators with index i. * @param i Which component to get. * @return The requested component. */ public NestedRandom get(int i) { return new NestedRandom(this, i); } /** * Returns an iterator through the same generators indexed using @get(int). * @return An iterator that returns all of the integer addressable components. */ public Iterator<NestedRandom> iterator() { return new Iterator<NestedRandom>() { AtomicInteger i = new AtomicInteger(-1); public boolean hasNext() { return true; } public NestedRandom next() { return NestedRandom.this.get(i.incrementAndGet()); } @Override public void remove() { throw new UnsupportedOperationException("Default operation"); } }; } /** * Return the random number generator associated with the current NestedRandom component. */ public Random random() { return new Random(hash(0)); } private NestedRandom(NestedRandom parent, int value) { this.parent = parent; content = null; seed = value; } private NestedRandom(NestedRandom parent, String component) { this.parent = parent; content = component; } private void hash(Hasher hasher) { if (content != null) { hasher.putString(content, Charsets.UTF_8); } else { hasher.putInt(seed); } if (parent != null) { parent.hash(hasher); } } private long hash(long seed) { Hasher h = Hashing.murmur3_128().newHasher(); h.putLong(seed); hash(h); return h.hash().asLong(); } }