blob: ebcc3744b188cfeed92527eaec0b1db4c0106002 [file] [log] [blame]
Abseil Teame9324d92019-06-21 13:11:42 -07001// Copyright 2019 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
Abseil Team36d37ab2019-07-25 04:03:57 -070015#ifndef ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_
16#define ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_
Abseil Teame9324d92019-06-21 13:11:42 -070017
18#include <cmath>
19#include <limits>
20#include <type_traits>
21
22#include "absl/meta/type_traits.h"
23
24namespace absl {
25template <typename IntType>
26class uniform_int_distribution;
27
28template <typename RealType>
29class uniform_real_distribution;
30
31// Interval tag types which specify whether the interval is open or closed
32// on either boundary.
33namespace random_internal {
34struct IntervalClosedClosedT {};
35struct IntervalClosedOpenT {};
36struct IntervalOpenClosedT {};
37struct IntervalOpenOpenT {};
Abseil Teame9324d92019-06-21 13:11:42 -070038
39// The functions
40// uniform_lower_bound(tag, a, b)
41// and
42// uniform_upper_bound(tag, a, b)
43// are used as implementation-details for absl::Uniform().
44//
45// Conceptually,
46// [a, b] == [uniform_lower_bound(IntervalClosedClosed, a, b),
47// uniform_upper_bound(IntervalClosedClosed, a, b)]
48// (a, b) == [uniform_lower_bound(IntervalOpenOpen, a, b),
49// uniform_upper_bound(IntervalOpenOpen, a, b)]
50// [a, b) == [uniform_lower_bound(IntervalClosedOpen, a, b),
51// uniform_upper_bound(IntervalClosedOpen, a, b)]
52// (a, b] == [uniform_lower_bound(IntervalOpenClosed, a, b),
53// uniform_upper_bound(IntervalOpenClosed, a, b)]
54//
55template <typename IntType, typename Tag>
56typename absl::enable_if_t<
57 absl::conjunction<
58 std::is_integral<IntType>,
59 absl::disjunction<std::is_same<Tag, IntervalOpenClosedT>,
60 std::is_same<Tag, IntervalOpenOpenT>>>::value,
61 IntType>
62uniform_lower_bound(Tag, IntType a, IntType) {
63 return a + 1;
64}
65
66template <typename FloatType, typename Tag>
67typename absl::enable_if_t<
68 absl::conjunction<
69 std::is_floating_point<FloatType>,
70 absl::disjunction<std::is_same<Tag, IntervalOpenClosedT>,
71 std::is_same<Tag, IntervalOpenOpenT>>>::value,
72 FloatType>
73uniform_lower_bound(Tag, FloatType a, FloatType b) {
74 return std::nextafter(a, b);
75}
76
77template <typename NumType, typename Tag>
78typename absl::enable_if_t<
79 absl::disjunction<std::is_same<Tag, IntervalClosedClosedT>,
80 std::is_same<Tag, IntervalClosedOpenT>>::value,
81 NumType>
82uniform_lower_bound(Tag, NumType a, NumType) {
83 return a;
84}
85
86template <typename IntType, typename Tag>
87typename absl::enable_if_t<
88 absl::conjunction<
89 std::is_integral<IntType>,
90 absl::disjunction<std::is_same<Tag, IntervalClosedOpenT>,
91 std::is_same<Tag, IntervalOpenOpenT>>>::value,
92 IntType>
93uniform_upper_bound(Tag, IntType, IntType b) {
94 return b - 1;
95}
96
97template <typename FloatType, typename Tag>
98typename absl::enable_if_t<
99 absl::conjunction<
100 std::is_floating_point<FloatType>,
101 absl::disjunction<std::is_same<Tag, IntervalClosedOpenT>,
102 std::is_same<Tag, IntervalOpenOpenT>>>::value,
103 FloatType>
104uniform_upper_bound(Tag, FloatType, FloatType b) {
105 return b;
106}
107
108template <typename IntType, typename Tag>
109typename absl::enable_if_t<
110 absl::conjunction<
111 std::is_integral<IntType>,
112 absl::disjunction<std::is_same<Tag, IntervalClosedClosedT>,
113 std::is_same<Tag, IntervalOpenClosedT>>>::value,
114 IntType>
115uniform_upper_bound(Tag, IntType, IntType b) {
116 return b;
117}
118
119template <typename FloatType, typename Tag>
120typename absl::enable_if_t<
121 absl::conjunction<
122 std::is_floating_point<FloatType>,
123 absl::disjunction<std::is_same<Tag, IntervalClosedClosedT>,
124 std::is_same<Tag, IntervalOpenClosedT>>>::value,
125 FloatType>
126uniform_upper_bound(Tag, FloatType, FloatType b) {
127 return std::nextafter(b, (std::numeric_limits<FloatType>::max)());
128}
129
130template <typename NumType>
131using UniformDistribution =
132 typename std::conditional<std::is_integral<NumType>::value,
133 absl::uniform_int_distribution<NumType>,
134 absl::uniform_real_distribution<NumType>>::type;
135
136template <typename TagType, typename NumType>
137struct UniformDistributionWrapper : public UniformDistribution<NumType> {
138 explicit UniformDistributionWrapper(NumType lo, NumType hi)
139 : UniformDistribution<NumType>(
140 uniform_lower_bound<NumType>(TagType{}, lo, hi),
141 uniform_upper_bound<NumType>(TagType{}, lo, hi)) {}
142};
143
144} // namespace random_internal
145} // namespace absl
146
Abseil Team36d37ab2019-07-25 04:03:57 -0700147#endif // ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_