Repository navigation
jinja : implement mixed type object keys #18955
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
0cb1d45
7c17e55
b3fa217
c929773
b04e1fd
eb8428a
0712934
2c1c417
a620d88
bf83cd4
be80c62
77e51ec
91774bf
fa1ef3f
80d0899
8eccc41
2160c0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| #include <string> | ||
| #include <sstream> | ||
| #include <algorithm> | ||
| #include <limits> | ||
|
|
||
| namespace jinja { | ||
|
|
||
|
|
@@ -46,4 +47,38 @@ static std::string fmt_error_with_source(const std::string & tag, const std::str | |
| return oss.str(); | ||
| } | ||
|
|
||
| // FNV-1a hash function that takes initial seed hash | ||
| // No need to worry about the whole hash_combine drama | ||
| // NOTE: **Never** pass a seed that is not a hash value originating from this function | ||
| static constexpr auto size_t_digits = std::numeric_limits<size_t>::digits; | ||
| static_assert(size_t_digits == 64 || size_t_digits == 32); | ||
|
|
||
| template <typename... Args> | ||
| static size_t hash_bytes(size_t seed, void const * bytes, size_t len, Args&&... args) noexcept | ||
| { | ||
| static_assert(sizeof...(args) % 2 == 0); | ||
| static constexpr size_t prime = size_t_digits == 64 ? 0x100000001b3 : 0x01000193; | ||
|
|
||
| unsigned char const * c = static_cast<unsigned char const *>(bytes); | ||
| unsigned char const * const e = c + len; | ||
|
|
||
| for (; c < e; ++c) { | ||
| seed = (seed ^ *c) * prime; | ||
| } | ||
|
|
||
| if constexpr (sizeof...(args) > 0) { | ||
| seed = hash_bytes(seed, std::forward<Args>(args)...); | ||
| } | ||
|
|
||
| return seed; | ||
| } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just thinking out loud in math terms: if we consider given input data and your "convenient" function therefore, but now, consider: (note: the property in practice, to prevent this, most hash functions use some kind of internal state such that: end of the math part. now, in term of speed, what I think can be nice & fun to make
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FNV-1a certainly has its flaws, it was mainly chosen for its simplicity and chainability, it performs well enough in terms of quality and speed here I think. Feel free to improve upon it if you wish though. :)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I ended up refactor this into a new struct called // Old notion:
size_t seed = hash_bytes(data0, len0);
seed = hash_bytes(data1, len1);
// ...
size_t output = hash_bytes(seed, dataN, lenN);
// New notion
hasher hash = hasher().update(data0, len0).update(data1, len1); // ...
size_t output = hash.digest();With this type of notion, we can in theory implement the notion of "internal state", though I won't add it because it's unnecessary (just mentioning here for completeness) The new notion should have the exact same mathematical properties as the old one (reflected by the new test cases in The result will be different from the old one though, because we are processing block of N bytes at once (on 64-bit system, we process 64/8 = 8 bytes). I expect most compilers will know how to vectorize it. If data is not a multiple of the block size, they will be buffered. I'll do another pass tomorrow to see if there are any other clean up needed. In the meantime, feel free to review my last commit and lmk if anything seems off to you. |
||
|
|
||
| template <typename... Args> | ||
| static size_t hash_bytes(void const * bytes, size_t len, Args&&... args) noexcept | ||
| { | ||
| static constexpr size_t seed = size_t_digits == 64 ? 0xcbf29ce484222325 : 0x811c9dc5; | ||
|
|
||
| return hash_bytes(seed, bytes, len, std::forward<Args>(args)...); | ||
| } | ||
|
|
||
| } // namespace jinja | ||
Uh oh!
There was an error while loading. Please reload this page.