ROSE 0.11.145.281
Combinatorics.h
1#ifndef ROSE_Combinatorics_H
2#define ROSE_Combinatorics_H
3
4#include <rosePublicConfig.h>
5
6#include <Rose/Constants.h>
7#include <ROSE_DEPRECATED.h>
8#include <ROSE_UNUSED.h>
9
10#include <algorithm>
11#include <cassert>
12#include <istream>
13#include <list>
14#include <memory>
15#include <ostream>
16#include <Rose/Exception.h>
17#include <Sawyer/Assert.h>
18#include <Sawyer/Synchronization.h>
19#include <stdexcept>
20#include <stdint.h>
21#include <string>
22#include <vector>
23
24#ifdef ROSE_HAVE_LIBGCRYPT
25#include <gcrypt.h>
26#endif
27
28namespace Rose {
29
31namespace Combinatorics {
32
34template<typename T>
35static T
36factorial(const T n) {
37 T retval = 1;
38 while (n>1) {
39 const T next = retval * n--;
40 assert(next > retval); // overflow; signed overflow is UB, so this likely doesn't work right when T is signed
41 retval = next;
42 }
43 return retval;
44}
45
47ROSE_DLL_API bool flip_coin();
48
56template<typename T>
57static void
58permute(std::vector<T> &values/*in,out*/, uint64_t pn, const size_t sz = UNLIMITED) {
59 if (UNLIMITED == sz)
60 sz = values.size();
61 assert(sz <= values.size());
62 assert(pn < factorial(sz));
63 for (size_t i = 0; i < sz; ++i) {
64 uint64_t radix = sz - i;
65 uint64_t idx = pn % radix;
66 std::swap(values[i + idx], values[i]);
67 pn /= radix;
68 }
69}
70
76template<typename T>
77void
78shuffle(std::vector<T> &vector, size_t nitems = UNLIMITED, size_t limit = UNLIMITED) {
79 nitems = std::min(nitems, vector.size());
80 limit = std::min(limit, nitems);
81
82 for (size_t i=0; i<limit; ++i) {
83 size_t j = Sawyer::fastRandomIndex(nitems);
84 std::swap(vector[i], vector[j]);
85 }
86}
87
113template<class T>
114void
115reorder(std::vector<T> &values, const std::vector<size_t> &remap) {
116 assert(values.size() == remap.size());
117
118 // O(n) implementation using a temporary vector. Alternatively, we could use an O(n^2) algorithm that uses constant space.
119 std::vector<T> old = values;
120 for (size_t i = 0; i < old.size(); ++i)
121 values[i] = old[remap[i]];
122}
123
137ROSE_DLL_API std::string toBase62String(uint64_t);
138
146ROSE_DLL_API uint64_t fromBase62String(const std::string& base62);
147
181class ROSE_DLL_API Hasher {
182public:
187 typedef std::vector<uint8_t> Digest;
188
191 public:
193 Exception(const std::string &mesg): Rose::Exception(mesg) {}
194 ~Exception() throw () {}
195 };
196
197protected:
198 Digest digest_;
199
200public:
201 virtual ~Hasher() {}
202
204 virtual void clear();
205
210 virtual const Digest& digest();
211
217 void insert(const std::string&);
218 void insert(uint64_t);
219 void insert(const uint8_t *bytes, size_t nBytes);
220 void insert(const std::vector<uint8_t>&);
221 void insert(std::istream&);
228 virtual void append(const uint8_t *message, size_t messageSize) = 0;
229
231 static std::string toString(const Digest&);
232
237 std::string toString();
238
245 uint64_t toU64();
246 uint64_t toU64(const Digest&);
249 // [Robb Matzke 2025-05-16]: deprecated; casting to another type should have "to" in the name, like "toString" above.
250 uint64_t make64Bits() ROSE_DEPRECATED("use toU64");
251 uint64_t make64Bits(const Digest&) ROSE_DEPRECATED("use toU64");
252
257 void print(std::ostream&);
258
265 public:
266 virtual std::shared_ptr<Hasher> create() const = 0;
267 virtual ~IHasherMaker() {}
268 };
269
282 template<typename T>
283 class HasherMaker : public IHasherMaker {
284 public:
290 HasherMaker(const std::string& hashType) {
291 HasherFactory::instance().registerMaker(hashType, this);
292 }
293
297 virtual std::shared_ptr<Hasher> create() const {
298 return std::make_shared<T>();
299 }
300 };
301
309 public:
314
315 // [Robb Matzke 2025-05-16]: deprecated; violates ROSE public function naming convention
316 static HasherFactory& Instance() ROSE_DEPRECATED("use instance");
317
321 void registerMaker(const std::string& hashType, IHasherMaker* createHasherPtr);
322
328 std::shared_ptr<Hasher> createHasher(const std::string& hashType) const;
329
330 private:
331 HasherFactory() {}
332
333 // Non-copyable
334 HasherFactory(const HasherFactory&) = delete;
335 HasherFactory& operator=(const HasherFactory&) = delete;
336
337 // Maps keys to @ref HasherMaker
338 std::map<std::string, IHasherMaker* > hashMakers;
339 };
340};
341
347template<int hashAlgorithmId>
348class HasherGcrypt: public Hasher {
349#ifdef ROSE_HAVE_LIBGCRYPT
350 gcry_md_hd_t md_;
351#endif
352
353public:
354 HasherGcrypt() {
355 #ifdef ROSE_HAVE_LIBGCRYPT
356 if (gcry_md_open(&md_, hashAlgorithmId, 0) != GPG_ERR_NO_ERROR)
357 throw Exception("cannot initialize libgcrypt hash " + std::string(gcry_md_algo_name(hashAlgorithmId)));
358 #else
359 throw Exception("ROSE was not configured with libgcrypt");
360 #endif
361 }
362
363 HasherGcrypt(const HasherGcrypt &other) {
364 #ifdef ROSE_HAVE_LIBGCRYPT
365 if (gcry_md_copy(&md_, other.md_) != GPG_ERR_NO_ERROR)
366 throw Exception("cannot copy libgcrypt hash " + std::string(gcry_md_algo_name(hashAlgorithmId)));
367 #else
368 ROSE_UNUSED(other);
369 throw Exception("ROSE was not configured with libgcrypt");
370 #endif
371 }
372
373 ~HasherGcrypt() {
374 #ifdef ROSE_HAVE_LIBGCRYPT
375 gcry_md_close(md_);
376 #endif
377 }
378
379 HasherGcrypt& operator=(const HasherGcrypt &other) {
380 #ifdef ROSE_HAVE_LIBGCRYPT
381 gcry_md_close(md_);
382 if (gcry_md_copy(&md_, other.md_) != GPG_ERR_NO_ERROR)
383 throw Exception("cannot copy libgcrypt hash " + std::string(gcry_md_algo_name(hashAlgorithmId)));
384 #else
385 ROSE_UNUSED(other);
386 throw Exception("ROSE was not configured with libgcrypt");
387 #endif
388 }
389
390 void clear() {
391 #ifdef ROSE_HAVE_LIBGCRYPT
392 gcry_md_reset(md_);
393 #endif
395 }
396
397 const Digest& digest() {
398 if (digest_.empty()) {
399 #ifdef ROSE_HAVE_LIBGCRYPT
400 gcry_md_final(md_);
401 digest_.resize(gcry_md_get_algo_dlen(hashAlgorithmId), 0);
402 uint8_t *d = gcry_md_read(md_, hashAlgorithmId);
403 ASSERT_not_null(d);
404 memcpy(&digest_[0], d, digest_.size());
405 #else
406 ASSERT_not_reachable("ROSE was not configured with libgcrypt");
407 #endif
408 }
409 return Hasher::digest();
410 }
411
412 void append(const uint8_t *message, size_t messageSize) {
413 ASSERT_require(message || 0==messageSize);
414 #ifdef ROSE_HAVE_LIBGCRYPT
415 if (!digest_.empty())
416 throw Exception("cannot append after returning digest");
417 if (messageSize > 0)
418 gcry_md_write(md_, message, messageSize);
419 #else
420 ASSERT_not_reachable("ROSE was not configured with libgcrypt");
421 #endif
422 }
423};
424
425#ifdef ROSE_HAVE_LIBGCRYPT
426typedef HasherGcrypt<GCRY_MD_MD5> HasherMd5;
427typedef HasherGcrypt<GCRY_MD_SHA1> HasherSha1;
428typedef HasherGcrypt<GCRY_MD_SHA256> HasherSha256;
429typedef HasherGcrypt<GCRY_MD_SHA384> HasherSha384;
430typedef HasherGcrypt<GCRY_MD_SHA512> HasherSha512;
431typedef HasherGcrypt<GCRY_MD_CRC32> HasherCrc32;
432#else // the template argument for the following unimplemented hashers is arbitrary and they can all be the same
439#endif
440
441
442
444class ROSE_DLL_API HasherFnv: public Hasher {
445 uint64_t partial_;
446public:
447 HasherFnv(): partial_(0xcbf29ce484222325ull) {}
448 const Digest& digest() override;
449 void append(const uint8_t *message, size_t messageSize) override;
450 uint64_t partial() const { return partial_; }
451};
452
456class ROSE_DLL_API HasherSha256Builtin: public Hasher {
457 static const uint32_t roundConstants_[64]; // statically-generated constants for the algorithm
458 uint32_t state_[8]; // 256 bits of state information
459 size_t processedBytes_; // number of message bytes hashed (excludes padding)
460 std::vector<uint8_t> leftoverBytes_; // message bytes inserted but not yet hashed
461public:
463 void clear() override;
464 const Digest& digest() override;
465 void append(const uint8_t *message, size_t messageSize) override;
466private:
467 uint8_t messageByte(size_t index, const uint8_t *message, size_t messageSize);
468 bool getNextChunk(const uint8_t* &message /*in,out*/, size_t &messageSize /*in,out*/, uint32_t words[16] /*out*/);
469 void accumulateChunk(const uint32_t chunk[16]);
470};
471
475template<class T, class U>
476std::vector<std::pair<T, U> >
477zip(const std::vector<T> &first, const std::vector<U> &second) {
478 size_t retvalSize = std::min(first.size(), second.size());
479 std::vector<std::pair<T, U> > retval;
480 retval.reserve(retvalSize);
481 for (size_t i = 0; i < retvalSize; ++i)
482 retval.push_back(std::pair<T, U>(first[i], second[i]));
483 return retval;
484}
485
487template<class T, class U>
488std::pair<std::vector<T>, std::vector<U> >
489unzip(const std::vector<std::pair<T, U> > &pairs) {
490 std::pair<std::vector<T>, std::vector<U> > retval;
491 retval.first.reserve(pairs.size());
492 retval.second.reserve(pairs.size());
493 for (size_t i = 0; i < pairs.size(); ++i) {
494 retval.first.push_back(pairs[i].first);
495 retval.second.push_back(pairs[i].second);
496 }
497 return retval;
498}
499
500} // namespace
501} // namespace
502
504
506ROSE_DLL_API std::ostream& operator<<(std::ostream&, Rose::Combinatorics::Hasher&);
507
508#endif
Fowler-Noll-Vo hashing using the Hasher interface.
void append(const uint8_t *message, size_t messageSize) override
Insert data into the digest.
const Digest & digest() override
Return the digest.
Hasher for any libgcrypt hash algorithm.
void append(const uint8_t *message, size_t messageSize)
Insert data into the digest.
void clear()
Reset the hasher to its initial state.
const Digest & digest()
Return the digest.
void append(const uint8_t *message, size_t messageSize) override
Insert data into the digest.
void clear() override
Reset the hasher to its initial state.
const Digest & digest() override
Return the digest.
Exception(const std::string &mesg)
Constructor.
A singleton that creates and returns Hashers by name.
static HasherFactory & instance()
Returns a reference to the HasherFactory singleton.
Templated to create any Hasher and register it with HasherFactory.
HasherMaker(const std::string &hashType)
Creates a HasherMaker and registers it with HasherFactory.
virtual std::shared_ptr< Hasher > create() const
Creates a Hasher.
Common subclass all the classes that construct Hashers.
void insert(const std::string &)
Insert data into the digest.
std::string toString()
String representation of the digest.
std::vector< uint8_t > Digest
The digest of the input message.
void insert(uint64_t)
Insert data into the digest.
static std::string toString(const Digest &)
Convert a digest to a hexadecimal string.
uint64_t toU64(const Digest &)
Returns the hash as a 64 bit int.
void insert(std::istream &)
Insert data into the digest.
virtual void clear()
Reset the hasher to its initial state.
virtual const Digest & digest()
Return the digest.
void insert(const uint8_t *bytes, size_t nBytes)
Insert data into the digest.
void insert(const std::vector< uint8_t > &)
Insert data into the digest.
virtual void append(const uint8_t *message, size_t messageSize)=0
Insert data into the digest.
uint64_t toU64()
Returns the hash as a 64 bit int.
Base class for all ROSE exceptions.
ROSE_DLL_API bool flip_coin()
Simulate flipping a coin.
HasherGcrypt< 0 > HasherSha1
SHA1 hasher.
std::vector< std::pair< T, U > > zip(const std::vector< T > &first, const std::vector< U > &second)
Convert two vectors to a vector of pairs.
HasherGcrypt< 0 > HasherSha384
SHA-384 hasher.
HasherGcrypt< 0 > HasherCrc32
ISO 3309 hasher.
void reorder(std::vector< T > &values, const std::vector< size_t > &remap)
Reorder the values of one vector according to another.
HasherGcrypt< 0 > HasherMd5
MD5 hasher.
void shuffle(std::vector< T > &vector, size_t nitems=UNLIMITED, size_t limit=UNLIMITED)
Shuffle the values of a vector.
std::pair< std::vector< T >, std::vector< U > > unzip(const std::vector< std::pair< T, U > > &pairs)
Convert a vector of pairs to a pair of vectors.
ROSE_DLL_API uint64_t fromBase62String(const std::string &base62)
Converts a base 62 string to a 64 bit int.
HasherGcrypt< 0 > HasherSha256
SHA-256 hasher.
ROSE_DLL_API std::string toBase62String(uint64_t)
Converts a 64 bit int to base 62.
HasherGcrypt< 0 > HasherSha512
SHA-512 hasher.
The ROSE library.
const size_t UNLIMITED
Effectively unlimited size.
Definition Constants.h:19
size_t fastRandomIndex(size_t n, size_t seed=0)
Thread-safe random number generator.