// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF 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.

// Date: Thu Dec 31 13:35:39 CST 2015

#ifndef BUTIL_FAST_RAND_H
#define BUTIL_FAST_RAND_H

#include <stdint.h>

namespace butil {

// Generate random values fast without global contentions.
// All functions in this header are thread-safe.

struct FastRandSeed {
    uint64_t s[2];
};

// Initialize the seed.
void init_fast_rand_seed(FastRandSeed* seed);

// Generate an unsigned 64-bit random number from thread-local or given seed.
// Cost: ~5ns
uint64_t fast_rand();
uint64_t fast_rand(FastRandSeed*);

// Generate an unsigned 64-bit random number inside [0, range) from
// thread-local seed.
// Returns 0 when range is 0.
// Cost: ~30ns
// Note that this can be used as an adapter for std::random_shuffle():
//   std::random_shuffle(myvector.begin(), myvector.end(), butil::fast_rand_less_than);
uint64_t fast_rand_less_than(uint64_t range);

// Generate a 64-bit random number inside [min, max] (inclusive!)
// from thread-local seed.
// NOTE: this function needs to be a template to be overloadable properly.
// Cost: ~30ns
template <typename T> T fast_rand_in(T min, T max) {
    extern int64_t fast_rand_in_64(int64_t min, int64_t max);
    extern uint64_t fast_rand_in_u64(uint64_t min, uint64_t max);
    if ((T)-1 < 0) {
        return fast_rand_in_64((int64_t)min, (int64_t)max);
    } else {
        return fast_rand_in_u64((uint64_t)min, (uint64_t)max);
    }
}

// Generate a random double in [0, 1) from thread-local seed.
// Cost: ~15ns
double fast_rand_double();

// Fills |output_length| bytes of |output| with random data.
void fast_rand_bytes(void* output, size_t output_length, uint8_t min);

}

#endif  // BUTIL_FAST_RAND_H