salted_seed_seq.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright 2017 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. #ifndef Y_ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_
  15. #define Y_ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_
  16. #include <cstdint>
  17. #include <cstdlib>
  18. #include <initializer_list>
  19. #include <iterator>
  20. #include <memory>
  21. #include <type_traits>
  22. #include <utility>
  23. #include <vector>
  24. #include "y_absl/container/inlined_vector.h"
  25. #include "y_absl/meta/type_traits.h"
  26. #include "y_absl/random/internal/seed_material.h"
  27. #include "y_absl/types/optional.h"
  28. #include "y_absl/types/span.h"
  29. namespace y_absl {
  30. Y_ABSL_NAMESPACE_BEGIN
  31. namespace random_internal {
  32. // This class conforms to the C++ Standard "Seed Sequence" concept
  33. // [rand.req.seedseq].
  34. //
  35. // A `SaltedSeedSeq` is meant to wrap an existing seed sequence and modify
  36. // generated sequence by mixing with extra entropy. This entropy may be
  37. // build-dependent or process-dependent. The implementation may change to be
  38. // have either or both kinds of entropy. If salt is not available sequence is
  39. // not modified.
  40. template <typename SSeq>
  41. class SaltedSeedSeq {
  42. public:
  43. using inner_sequence_type = SSeq;
  44. using result_type = typename SSeq::result_type;
  45. SaltedSeedSeq() : seq_(y_absl::make_unique<SSeq>()) {}
  46. template <typename Iterator>
  47. SaltedSeedSeq(Iterator begin, Iterator end)
  48. : seq_(y_absl::make_unique<SSeq>(begin, end)) {}
  49. template <typename T>
  50. SaltedSeedSeq(std::initializer_list<T> il)
  51. : SaltedSeedSeq(il.begin(), il.end()) {}
  52. SaltedSeedSeq(const SaltedSeedSeq&) = delete;
  53. SaltedSeedSeq& operator=(const SaltedSeedSeq&) = delete;
  54. SaltedSeedSeq(SaltedSeedSeq&&) = default;
  55. SaltedSeedSeq& operator=(SaltedSeedSeq&&) = default;
  56. template <typename RandomAccessIterator>
  57. void generate(RandomAccessIterator begin, RandomAccessIterator end) {
  58. using U = typename std::iterator_traits<RandomAccessIterator>::value_type;
  59. // The common case is that generate is called with ContiguousIterators
  60. // to uint arrays. Such contiguous memory regions may be optimized,
  61. // which we detect here.
  62. using TagType = y_absl::conditional_t<
  63. (std::is_same<U, uint32_t>::value &&
  64. (std::is_pointer<RandomAccessIterator>::value ||
  65. std::is_same<RandomAccessIterator,
  66. typename std::vector<U>::iterator>::value)),
  67. ContiguousAndUint32Tag, DefaultTag>;
  68. if (begin != end) {
  69. generate_impl(TagType{}, begin, end, std::distance(begin, end));
  70. }
  71. }
  72. template <typename OutIterator>
  73. void param(OutIterator out) const {
  74. seq_->param(out);
  75. }
  76. size_t size() const { return seq_->size(); }
  77. private:
  78. struct ContiguousAndUint32Tag {};
  79. struct DefaultTag {};
  80. // Generate which requires the iterators are contiguous pointers to uint32_t.
  81. // Fills the initial seed buffer the underlying SSeq::generate() call,
  82. // then mixes in the salt material.
  83. template <typename Contiguous>
  84. void generate_impl(ContiguousAndUint32Tag, Contiguous begin, Contiguous end,
  85. size_t n) {
  86. seq_->generate(begin, end);
  87. const uint32_t salt = y_absl::random_internal::GetSaltMaterial().value_or(0);
  88. auto span = y_absl::Span<uint32_t>(&*begin, n);
  89. MixIntoSeedMaterial(y_absl::MakeConstSpan(&salt, 1), span);
  90. }
  91. // The uncommon case for generate is that it is called with iterators over
  92. // some other buffer type which is assignable from a 32-bit value. In this
  93. // case we allocate a temporary 32-bit buffer and then copy-assign back
  94. // to the initial inputs.
  95. template <typename RandomAccessIterator>
  96. void generate_impl(DefaultTag, RandomAccessIterator begin,
  97. RandomAccessIterator, size_t n) {
  98. // Allocates a seed buffer of `n` elements, generates the seed, then
  99. // copies the result into the `out` iterator.
  100. y_absl::InlinedVector<uint32_t, 8> data(n, 0);
  101. generate_impl(ContiguousAndUint32Tag{}, data.begin(), data.end(), n);
  102. std::copy(data.begin(), data.end(), begin);
  103. }
  104. // Because [rand.req.seedseq] is not required to be copy-constructible,
  105. // copy-assignable nor movable, we wrap it with unique pointer to be able
  106. // to move SaltedSeedSeq.
  107. std::unique_ptr<SSeq> seq_;
  108. };
  109. // is_salted_seed_seq indicates whether the type is a SaltedSeedSeq.
  110. template <typename T, typename = void>
  111. struct is_salted_seed_seq : public std::false_type {};
  112. template <typename T>
  113. struct is_salted_seed_seq<
  114. T, typename std::enable_if<std::is_same<
  115. T, SaltedSeedSeq<typename T::inner_sequence_type>>::value>::type>
  116. : public std::true_type {};
  117. // MakeSaltedSeedSeq returns a salted variant of the seed sequence.
  118. // When provided with an existing SaltedSeedSeq, returns the input parameter,
  119. // otherwise constructs a new SaltedSeedSeq which embodies the original
  120. // non-salted seed parameters.
  121. template <
  122. typename SSeq, //
  123. typename EnableIf = y_absl::enable_if_t<is_salted_seed_seq<SSeq>::value>>
  124. SSeq MakeSaltedSeedSeq(SSeq&& seq) {
  125. return SSeq(std::forward<SSeq>(seq));
  126. }
  127. template <
  128. typename SSeq, //
  129. typename EnableIf = y_absl::enable_if_t<!is_salted_seed_seq<SSeq>::value>>
  130. SaltedSeedSeq<typename std::decay<SSeq>::type> MakeSaltedSeedSeq(SSeq&& seq) {
  131. using sseq_type = typename std::decay<SSeq>::type;
  132. using result_type = typename sseq_type::result_type;
  133. y_absl::InlinedVector<result_type, 8> data;
  134. seq.param(std::back_inserter(data));
  135. return SaltedSeedSeq<sseq_type>(data.begin(), data.end());
  136. }
  137. } // namespace random_internal
  138. Y_ABSL_NAMESPACE_END
  139. } // namespace y_absl
  140. #endif // Y_ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_