ROSE 0.11.145.141
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_UNUSED.h>
8
9#include <boost/shared_ptr.hpp>
10
11#include <algorithm>
12#include <cassert>
13#include <istream>
14#include <list>
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(T n)
37{
38 T retval = 1;
39 while (n>1) {
40 T next = retval * n--;
41 assert(next>retval); // overflow
42 retval = next;
43 }
44 return retval;
45}
46
48ROSE_DLL_API bool flip_coin();
49
55template<typename T>
56static void
57permute(std::vector<T> &values/*in,out*/, uint64_t pn, size_t sz = UNLIMITED)
58{
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{
80 nitems = std::min(nitems, vector.size());
81 limit = std::min(limit, nitems);
82
83 for (size_t i=0; i<limit; ++i) {
84 size_t j = Sawyer::fastRandomIndex(nitems);
85 std::swap(vector[i], vector[j]);
86 }
87}
88
114template<class T>
115void
116reorder(std::vector<T> &values, const std::vector<size_t> &remap) {
117 assert(values.size() == remap.size());
118
119 // O(n) implementation using a temporary vector. Alternatively, we could use an O(n^2) algorithm that uses constant space.
120 std::vector<T> old = values;
121 for (size_t i = 0; i < old.size(); ++i)
122 values[i] = old[remap[i]];
123}
124
131ROSE_DLL_API std::string toBase62String(uint64_t num);
132
139ROSE_DLL_API uint64_t fromBase62String(const std::string& base62);
140
174class ROSE_DLL_API Hasher {
175public:
180 typedef std::vector<uint8_t> Digest;
181
184 public:
186 Exception(const std::string &mesg): Rose::Exception(mesg) {}
187 ~Exception() throw () {}
188 };
189
190protected:
191 Digest digest_;
192
193public:
194 virtual ~Hasher() {}
195
197 virtual void clear() { digest_ = Digest(); }
198
203 virtual const Digest& digest() { return digest_; }
204
210 void insert(const std::string &x) { append((const uint8_t*)x.c_str(), x.size()); }
211 void insert(uint64_t x) { append((uint8_t*)&x, sizeof x); }
212 void insert(const uint8_t *x, size_t size) { append(x, size); }
213 void insert(const std::vector<uint8_t> &v) { append(v.data(), v.size()); }
214 void insert(std::istream &stream) {
215 char buf[4096]; // multiple of 64
216 while (stream.good()) {
217 stream.read(buf, sizeof buf);
218 append((const uint8_t*)buf, stream.gcount());
219 }
220 if (!stream.eof())
221 throw Hasher::Exception("failed to read data from file");
222 }
229 virtual void append(const uint8_t *message, size_t messageSize) = 0;
230
232 static std::string toString(const Digest&);
233
238 std::string toString();
239
247 uint64_t make64Bits();
248 uint64_t make64Bits(const Digest&);
255 void print(std::ostream&);
256
264 {
265 public:
266 virtual boost::shared_ptr<Hasher> create() const = 0;
267 virtual ~IHasherMaker() {}
268 };
269
285 template<typename T>
287 {
288 public:
297 HasherMaker(const std::string& hashType)
298 {
299 HasherFactory::Instance().registerMaker(hashType, this);
300 }
301
306 virtual boost::shared_ptr<Hasher> create() const
307 {
308 T* hasher = new T;
309 boost::shared_ptr<Hasher> hashPtr(hasher);
310 return hashPtr;
311 }
312
313 };
314
327 {
328 public:
332
335 void registerMaker(const std::string& hashType, IHasherMaker* createHasherPtr);
336
344 boost::shared_ptr<Hasher> createHasher(const std::string& hashType) const;
345
346 private:
347 HasherFactory() {}
348
350 HasherFactory(const HasherFactory& other);
352 HasherFactory& operator=(const HasherFactory& other);
353
355 std::map<std::string, IHasherMaker* > hashMakers;
356 };
357};
358
364template<int hashAlgorithmId>
365class HasherGcrypt: public Hasher {
366#ifdef ROSE_HAVE_LIBGCRYPT
367 gcry_md_hd_t md_;
368#endif
369
370public:
371 HasherGcrypt() {
372 #ifdef ROSE_HAVE_LIBGCRYPT
373 if (gcry_md_open(&md_, hashAlgorithmId, 0) != GPG_ERR_NO_ERROR)
374 throw Exception("cannot initialize libgcrypt hash " + std::string(gcry_md_algo_name(hashAlgorithmId)));
375 #else
376 throw Exception("ROSE was not configured with libgcrypt");
377 #endif
378 }
379
380 HasherGcrypt(const HasherGcrypt &other) {
381 #ifdef ROSE_HAVE_LIBGCRYPT
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 ~HasherGcrypt() {
391 #ifdef ROSE_HAVE_LIBGCRYPT
392 gcry_md_close(md_);
393 #endif
394 }
395
396 HasherGcrypt& operator=(const HasherGcrypt &other) {
397 #ifdef ROSE_HAVE_LIBGCRYPT
398 gcry_md_close(md_);
399 if (gcry_md_copy(&md_, other.md_) != GPG_ERR_NO_ERROR)
400 throw Exception("cannot copy libgcrypt hash " + std::string(gcry_md_algo_name(hashAlgorithmId)));
401 #else
402 ROSE_UNUSED(other);
403 throw Exception("ROSE was not configured with libgcrypt");
404 #endif
405 }
406
407 void clear() {
408 #ifdef ROSE_HAVE_LIBGCRYPT
409 gcry_md_reset(md_);
410 #endif
412 }
413
414 const Digest& digest() {
415 if (digest_.empty()) {
416 #ifdef ROSE_HAVE_LIBGCRYPT
417 gcry_md_final(md_);
418 digest_.resize(gcry_md_get_algo_dlen(hashAlgorithmId), 0);
419 uint8_t *d = gcry_md_read(md_, hashAlgorithmId);
420 ASSERT_not_null(d);
421 memcpy(&digest_[0], d, digest_.size());
422 #else
423 ASSERT_not_reachable("ROSE was not configured with libgcrypt");
424 #endif
425 }
426 return Hasher::digest();
427 }
428
429 void append(const uint8_t *message, size_t messageSize) {
430 ASSERT_require(message || 0==messageSize);
431 #ifdef ROSE_HAVE_LIBGCRYPT
432 if (!digest_.empty())
433 throw Exception("cannot append after returning digest");
434 if (messageSize > 0)
435 gcry_md_write(md_, message, messageSize);
436 #else
437 ASSERT_not_reachable("ROSE was not configured with libgcrypt");
438 #endif
439 }
440};
441
442#ifdef ROSE_HAVE_LIBGCRYPT
443typedef HasherGcrypt<GCRY_MD_MD5> HasherMd5;
444typedef HasherGcrypt<GCRY_MD_SHA1> HasherSha1;
445typedef HasherGcrypt<GCRY_MD_SHA256> HasherSha256;
446typedef HasherGcrypt<GCRY_MD_SHA384> HasherSha384;
447typedef HasherGcrypt<GCRY_MD_SHA512> HasherSha512;
448typedef HasherGcrypt<GCRY_MD_CRC32> HasherCrc32;
449#else // the template argument for the following unimplemented hashers is arbitrary and they can all be the same
456#endif
457
458
459
461class ROSE_DLL_API HasherFnv: public Hasher {
462 uint64_t partial_;
463public:
464 HasherFnv(): partial_(0xcbf29ce484222325ull) {}
465 const Digest& digest() override;
466 void append(const uint8_t *message, size_t messageSize) override;
467 uint64_t partial() const { return partial_; }
468};
469
473class ROSE_DLL_API HasherSha256Builtin: public Hasher {
474 static const uint32_t roundConstants_[64]; // statically-generated constants for the algorithm
475 uint32_t state_[8]; // 256 bits of state information
476 size_t processedBytes_; // number of message bytes hashed (excludes padding)
477 std::vector<uint8_t> leftoverBytes_; // message bytes inserted but not yet hashed
478public:
480 void clear() override;
481 const Digest& digest() override;
482 void append(const uint8_t *message, size_t messageSize) override;
483private:
484 uint8_t messageByte(size_t index, const uint8_t *message, size_t messageSize);
485 bool getNextChunk(const uint8_t* &message /*in,out*/, size_t &messageSize /*in,out*/, uint32_t words[16] /*out*/);
486 void accumulateChunk(const uint32_t chunk[16]);
487};
488
492template<class T, class U>
493std::vector<std::pair<T, U> >
494zip(const std::vector<T> &first, const std::vector<U> &second) {
495 size_t retvalSize = std::min(first.size(), second.size());
496 std::vector<std::pair<T, U> > retval;
497 retval.reserve(retvalSize);
498 for (size_t i = 0; i < retvalSize; ++i)
499 retval.push_back(std::pair<T, U>(first[i], second[i]));
500 return retval;
501}
502
504template<class T, class U>
505std::pair<std::vector<T>, std::vector<U> >
506unzip(const std::vector<std::pair<T, U> > &pairs) {
507 std::pair<std::vector<T>, std::vector<U> > retval;
508 retval.first.reserve(pairs.size());
509 retval.second.reserve(pairs.size());
510 for (size_t i = 0; i < pairs.size(); ++i) {
511 retval.first.push_back(pairs[i].first);
512 retval.second.push_back(pairs[i].second);
513 }
514 return retval;
515}
516
517} // namespace
518} // namespace
519
521
523ROSE_DLL_API std::ostream& operator<<(std::ostream&, Rose::Combinatorics::Hasher&);
524
525#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.
HasherFactory is a singleton that creates and returns Hashers by name.
void registerMaker(const std::string &hashType, IHasherMaker *createHasherPtr)
Adds a new @HasherMaker to the HasherFactory.
static HasherFactory & Instance()
Returns a reference to the HasherFactory singleton.
boost::shared_ptr< Hasher > createHasher(const std::string &hashType) const
Creates a registered Hasher by type from the map.
Templated to create any Hasher and register it with HasherFactory.
virtual boost::shared_ptr< Hasher > create() const
Creates a Hasher (the type of Hasher is determined by the template T) and returns it as a shared_ptr.
HasherMaker(const std::string &hashType)
Creates a HasherMaker and registers it with HasherFactory.
Common subclass all the classes that construct Hashers (for the HasherFactory)
void insert(const std::string &x)
Insert data into the digest.
void insert(uint64_t x)
Insert data into the digest.
uint64_t make64Bits(const Digest &)
Returns the hash as a 64 bit int.
std::string toString()
String representation of the digest.
std::vector< uint8_t > Digest
The digest of the input message.
void insert(const std::vector< uint8_t > &v)
Insert data into the digest.
static std::string toString(const Digest &)
Convert a digest to a hexadecimal string.
virtual void clear()
Reset the hasher to its initial state.
virtual const Digest & digest()
Return the digest.
void print(std::ostream &)
Print a hash to a stream.
uint64_t make64Bits()
Returns the hash as a 64 bit int.
void insert(std::istream &stream)
Insert data into the digest.
void insert(const uint8_t *x, size_t size)
Insert data into the digest.
virtual void append(const uint8_t *message, size_t messageSize)=0
Insert data into the digest.
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.
ROSE_DLL_API std::string toBase62String(uint64_t num)
Converts a 64 bit in to base 62 (All letters and numbers).
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 (All letters and numbers) number to a 64 bit int.
HasherGcrypt< 0 > HasherSha256
SHA-256 hasher.
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.