├── Log.h ├── dpf.h ├── Log.cpp ├── Defines.cpp ├── CMakeLists.txt ├── LICENSE ├── hashdatastore.h ├── Readme.md ├── Defines.h ├── PRNG.cpp ├── AES.h ├── test.cpp ├── alignment_allocator.h ├── main.cpp ├── bench.cpp ├── PRNG.h ├── dpf.cpp ├── AES.cpp └── gsl └── gsl-lite.hpp /Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Defines.h" 4 | 5 | #define LOGGING_VERBOSE 0 6 | 7 | class Log { 8 | public: 9 | static void v(const char* tag, const char *format, ...); 10 | static void v(const char* tag, const block& b); 11 | }; 12 | -------------------------------------------------------------------------------- /dpf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Defines.h" 7 | namespace DPF { 8 | std::pair, std::vector > Gen(size_t alpha, size_t logn); 9 | bool Eval(const std::vector& key, size_t x, size_t logn); 10 | std::vector EvalFull(const std::vector& key, size_t logn); 11 | std::vector EvalFull8(const std::vector& key, size_t logn); 12 | } 13 | -------------------------------------------------------------------------------- /Log.cpp: -------------------------------------------------------------------------------- 1 | #include "Log.h" 2 | #include 3 | #include 4 | 5 | 6 | void Log::v(const char* tag, const char *format, ...) { 7 | if(LOGGING_VERBOSE) { 8 | va_list args; 9 | va_start(args, format); 10 | 11 | printf("[%s] ", tag); 12 | vprintf(format, args); 13 | printf("\n"); 14 | } 15 | 16 | } 17 | 18 | void Log::v(const char *tag, const block &b) { 19 | if(LOGGING_VERBOSE) { 20 | printf("[%s] ", tag); 21 | for (size_t i = 0; i < sizeof(block); i++) { 22 | // for(ssize_t i = sizeof(block)-1; i >= 0; i--) { 23 | printf("%02X", ((uint8_t *) &b)[i]); 24 | } 25 | printf("\n"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Defines.cpp: -------------------------------------------------------------------------------- 1 | #include "Defines.h" 2 | #include 3 | #include 4 | 5 | 6 | const block ZeroBlock = _mm_set_epi64x(0, 0); 7 | const block LSBBlock = _mm_set_epi64x(0, 1); 8 | const block MSBBlock = _mm_set_epi64x(1ULL<<63, 0); 9 | const block AllOneBlock = _mm_set_epi64x(uint64_t(-1), uint64_t(-1)); 10 | const block TestBlock = ([]() {block aa; memset(&aa, 0xaa, sizeof(block)); return aa; })(); 11 | 12 | void split(const std::string &s, char delim, std::vector &elems) { 13 | std::stringstream ss(s); 14 | std::string item; 15 | while (std::getline(ss, item, delim)) { 16 | elems.push_back(item); 17 | } 18 | } 19 | 20 | std::vector split(const std::string &s, char delim) { 21 | std::vector elems; 22 | split(s, delim, elems); 23 | return elems; 24 | } 25 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(DPFPIR) 2 | cmake_minimum_required(VERSION 3.4.1) 3 | 4 | enable_language(C CXX) 5 | set(CMAKE_CXX_STANDARD 14) 6 | 7 | 8 | set(SRCS 9 | AES.cpp 10 | Defines.cpp 11 | Log.cpp 12 | PRNG.cpp 13 | dpf.cpp 14 | hashdatastore.cpp) 15 | 16 | set(CMAKE_C_FLAGS "-ffunction-sections -Wall -maes -msse2 -msse4.1 -mavx2 -mpclmul -Wfatal-errors -pthread -Wno-strict-overflow -fPIC -Wno-ignored-attributes") 17 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++14") 18 | 19 | # Select flags. 20 | SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") 21 | SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO " -O2 -g -ggdb -rdynamic") 22 | SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -ggdb -rdynamic") 23 | 24 | add_executable(dpf_pir ${SRCS} main.cpp) 25 | target_link_libraries(dpf_pir crypto) 26 | 27 | add_executable(bench ${SRCS} bench.cpp) 28 | target_link_libraries(bench crypto) 29 | 30 | add_executable(dpf_tests ${SRCS} test.cpp) 31 | target_link_libraries(dpf_tests crypto) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Daniel Kales 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /hashdatastore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "alignment_allocator.h" 8 | 9 | 10 | class hashdatastore { 11 | public: 12 | typedef __m256i hash_type; 13 | 14 | hashdatastore() = default; 15 | 16 | void reserve(size_t n) { data_.reserve(n); } 17 | void push_back(const hash_type& data) { data_.push_back(data); } 18 | void push_back(hash_type&& data) { data_.push_back(data); } 19 | 20 | void dummy(size_t n) { data_.resize(n, _mm256_set_epi64x(1,2,3,4)); } 21 | 22 | size_t size() const { return data_.size(); } 23 | 24 | hash_type answer_pir1(const std::vector& indexing) const; 25 | hash_type answer_pir2(const std::vector& indexing) const; 26 | hash_type answer_pir3(const std::vector& indexing) const; 27 | hash_type answer_pir4(const std::vector& indexing) const; 28 | hash_type answer_pir5(const std::vector& indexing) const; 29 | hash_type answer_pir_idea_speed_comparison(const std::vector& indexing) const; 30 | 31 | 32 | private: 33 | std::vector > data_; 34 | 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # C++ DPF-PIR library 2 | 3 | This is a high-performance implementation of private information retrieval (PIR) 4 | based on distributed point functions (DPF). As this is a multi-server 5 | (more specifically a 2-server) PIR, we need two *non-colluding* servers 6 | with identical databases. For our use case, where this DPF-PIR is being used in a 7 | Certificate Transparency (CT) log server, we specialize on databases of SHA-256 hash 8 | values, which are stored in a *hashdatastore* object. This aligns nicely with the use 9 | of AVX/AVX2 instructions to speed up calculations. We also make use of AES-NI instructions 10 | to create a high-performance PRF. 11 | 12 | 13 | ## Executing Microbenchmarks 14 | Example execution of microbenchmarks for a tree with 2^22 elements. 15 | 16 | ``` 17 | mkdir build && cd build 18 | cmake .. -DCMAKE_BUILD_TYPE=Release 19 | make 20 | ./dpf_pir 22 21 | ``` 22 | 23 | ## References 24 | 25 | Some parts like the AES-NI implementation are taken from Peter Rindal's public domain [CryptoTools](https://github.com/ladnir/cryptoTools/). 26 | 27 | [Paper](http://www.ramacher.at/_static/papers/ct-privacy.pdf): *Daniel Kales, Olamide Omolola, Sebastian Ramacher*. **Revisting User Privacy for Certificate Transparency**. EuroS&P 2019 28 | -------------------------------------------------------------------------------- /Defines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include "gsl/gsl-lite.hpp" 9 | 10 | #define STRINGIZE_DETAIL(x) #x 11 | #define STRINGIZE(x) STRINGIZE_DETAIL(x) 12 | #define LOCATION __FILE__ ":" STRINGIZE(__LINE__) 13 | 14 | template using span = gsl::span; 15 | 16 | typedef __m128i block; 17 | typedef union { 18 | __m128i reg; 19 | uint8_t arr[16]; 20 | } reg_arr_union; 21 | 22 | inline block toBlock(const uint8_t* in) { return _mm_set_epi64x(((uint64_t*)in)[1], ((uint64_t*)in)[0]);} 23 | //inline void fromBlock(uint8_t* out, const block& in) {vst1q_u8(out, in);} 24 | inline block dupUint64(uint64_t val) { return _mm_set_epi64x(val, val);} 25 | 26 | inline bool eq(const block& lhs, const block& rhs) 27 | { 28 | block neq = _mm_xor_si128(lhs, rhs); 29 | return _mm_test_all_zeros(neq, neq) != 0; 30 | } 31 | 32 | inline bool neq(const block& lhs, const block& rhs) 33 | { 34 | block neq = _mm_xor_si128(lhs, rhs); 35 | return _mm_test_all_zeros(neq, neq) == 0; 36 | } 37 | 38 | inline bool is_zero(const block& b) { 39 | return _mm_test_all_zeros(b, b); 40 | } 41 | 42 | extern const block ZeroBlock; 43 | extern const block LSBBlock; 44 | extern const block MSBBlock; 45 | extern const block AllOneBlock; 46 | extern const block TestBlock; 47 | 48 | 49 | void split(const std::string &s, char delim, std::vector &elems); 50 | std::vector split(const std::string &s, char delim); 51 | -------------------------------------------------------------------------------- /PRNG.cpp: -------------------------------------------------------------------------------- 1 | #include "PRNG.h" 2 | 3 | #include 4 | #include 5 | 6 | PRNG::PRNG(const block& seed, uint64_t bufferSize) 7 | : 8 | mBytesIdx(0), 9 | mBlockIdx(0) 10 | { 11 | SetSeed(seed, bufferSize); 12 | } 13 | 14 | PRNG::PRNG(PRNG && s) : 15 | mBuffer(std::move(s.mBuffer)), 16 | mAes(std::move(s.mAes)), 17 | mBytesIdx(s.mBytesIdx), 18 | mBlockIdx(s.mBlockIdx), 19 | mBufferByteCapacity(s.mBufferByteCapacity) 20 | { 21 | s.mBuffer.resize(0); 22 | memset(&s.mAes, 0, sizeof(AES)); 23 | s.mBytesIdx = 0; 24 | s.mBlockIdx = 0; 25 | s.mBufferByteCapacity = 0; 26 | } 27 | 28 | 29 | void PRNG::SetSeed(const block& seed, uint64_t bufferSize) 30 | { 31 | mAes.setKey(seed); 32 | mBlockIdx = 0; 33 | 34 | if (mBuffer.size() == 0) 35 | { 36 | mBuffer.resize(bufferSize); 37 | mBufferByteCapacity = (sizeof(block) * bufferSize); 38 | } 39 | 40 | 41 | refillBuffer(); 42 | } 43 | 44 | uint8_t PRNG::getBit() { return get(); } 45 | 46 | const block PRNG::getSeed() const 47 | { 48 | if(mBuffer.size()) 49 | return mAes.key; 50 | 51 | throw std::runtime_error("PRNG has not been keyed " LOCATION); 52 | } 53 | 54 | void PRNG::refillBuffer() 55 | { 56 | if (mBuffer.size() == 0) 57 | throw std::runtime_error("PRNG has not been keyed " LOCATION); 58 | 59 | mAes.encryptCTR(mBlockIdx, mBuffer.size(), mBuffer.data()); 60 | mBlockIdx += mBuffer.size(); 61 | mBytesIdx = 0; 62 | } 63 | -------------------------------------------------------------------------------- /AES.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Defines.h" 6 | 7 | 8 | #include 9 | #include 10 | 11 | class AES { 12 | public: 13 | AES(); 14 | AES(const block& key); 15 | AES(const uint8_t* key); 16 | 17 | void setKey(const block& key); 18 | void setKey(const uint8_t* key); 19 | 20 | void encryptECB(const block& plaintext, block& ciphertext) const; 21 | block encryptECB(const block& plaintext) const { 22 | block tmp; 23 | encryptECB(plaintext, tmp); 24 | return tmp; 25 | } 26 | void encryptECB_MMO(const block& plaintext, block& ciphertext) const; 27 | block encryptECB_MMO(const block& plaintext) const { 28 | block tmp; 29 | encryptECB_MMO(plaintext, tmp); 30 | return tmp; 31 | } 32 | 33 | void decryptECB(const block& ciphertext, block& plaintext) const; 34 | block decryptECB(const block& ciphertext) const { 35 | block tmp; 36 | decryptECB(ciphertext, tmp); 37 | return tmp; 38 | } 39 | void encryptECBBlocks(const block* plaintexts, uint64_t blockLength, block* ciphertexts) const; 40 | void encryptECB_MMO_Blocks(const block* plaintexts, uint64_t blockLength, block* ciphertexts) const; 41 | 42 | void encryptCTR(uint64_t baseIdx, uint64_t blockLength, block * ciphertext) const; 43 | block key; 44 | private: 45 | block mRoundKeysEnc[11]; 46 | block mRoundKeysDec[11]; 47 | }; 48 | 49 | // An AES instance with a fixed and public key 50 | extern const AES mAesFixedKey; 51 | extern const AES mAesFixedKey2; 52 | 53 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include "dpf.h" 2 | #include "hashdatastore.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | int testEvalFull8() { 9 | 10 | size_t N = 11; 11 | auto keys = DPF::Gen(0, N); 12 | auto a = keys.first; 13 | std::vector aaaa = DPF::EvalFull(a, N); 14 | std::vector bbbb = DPF::EvalFull8(a, N); 15 | 16 | if(aaaa == bbbb) { 17 | return 0; 18 | } 19 | else { 20 | std::cout << "EvalFull and EvalFull8 differ\n"; 21 | std::cout << "EvalFull size: " << aaaa.size() << " EvalFull8 size: " << bbbb.size() << std::endl; 22 | for(size_t i = 0; i < aaaa.size(); i++) { 23 | if(aaaa[i] != bbbb[i]) { 24 | std::cout << "at pos " << i << std::endl; 25 | } 26 | } 27 | return -1; 28 | } 29 | } 30 | 31 | int testCorr() { 32 | size_t N = 20; 33 | hashdatastore store; 34 | store.reserve(1ULL << N); 35 | for (size_t i = 0; i < (1ULL << N); i++) { 36 | store.push_back(_mm256_set_epi64x(i, i, i, i)); 37 | } 38 | 39 | auto keys = DPF::Gen(123456, N); 40 | auto a = keys.first; 41 | auto b = keys.second; 42 | std::vector aaaa = DPF::EvalFull8(a, N); 43 | std::vector bbbb = DPF::EvalFull8(b, N); 44 | hashdatastore::hash_type answerA = store.answer_pir2(aaaa); 45 | hashdatastore::hash_type answerB = store.answer_pir2(bbbb); 46 | hashdatastore::hash_type answer = _mm256_xor_si256(answerA, answerB); 47 | if(_mm256_extract_epi64(answer, 0) == 123456) { 48 | return 0; 49 | } else { 50 | std::cout << "PIR answer wrong\n"; 51 | return -1; 52 | } 53 | 54 | } 55 | 56 | int main(int argc, char** argv) { 57 | int res = 0; 58 | res |= testEvalFull8(); 59 | res |= testCorr(); 60 | return res; 61 | } -------------------------------------------------------------------------------- /alignment_allocator.h: -------------------------------------------------------------------------------- 1 | #ifndef ALIGNMENT_ALLOCATOR_H 2 | #define ALIGNMENT_ALLOCATOR_H 3 | // taken from https://stackoverflow.com/a/8545389 4 | 5 | #include 6 | #include 7 | 8 | template 9 | class AlignmentAllocator { 10 | public: 11 | typedef T value_type; 12 | typedef std::size_t size_type; 13 | typedef std::ptrdiff_t difference_type; 14 | 15 | typedef T * pointer; 16 | typedef const T * const_pointer; 17 | 18 | typedef T & reference; 19 | typedef const T & const_reference; 20 | 21 | public: 22 | inline AlignmentAllocator () throw () { } 23 | 24 | template 25 | inline AlignmentAllocator (const AlignmentAllocator &) throw () { } 26 | 27 | inline ~AlignmentAllocator () throw () { } 28 | 29 | inline pointer adress (reference r) { 30 | return &r; 31 | } 32 | 33 | inline const_pointer adress (const_reference r) const { 34 | return &r; 35 | } 36 | 37 | inline pointer allocate (size_type n) { 38 | return (pointer)_mm_malloc(n*sizeof(value_type), N); 39 | } 40 | 41 | inline void deallocate (pointer p, size_type) { 42 | _mm_free(p); 43 | } 44 | 45 | inline void construct (pointer p, const value_type & wert) { 46 | new (p) value_type (wert); 47 | } 48 | 49 | inline void destroy (pointer p) { 50 | p->~value_type (); 51 | } 52 | 53 | inline size_type max_size () const throw () { 54 | return size_type (-1) / sizeof (value_type); 55 | } 56 | 57 | template 58 | struct rebind { 59 | typedef AlignmentAllocator other; 60 | }; 61 | 62 | bool operator!=(const AlignmentAllocator& other) const { 63 | return !(*this == other); 64 | } 65 | 66 | // Returns true if and only if storage allocated from *this 67 | // can be deallocated from other, and vice versa. 68 | // Always returns true for stateless allocators. 69 | bool operator==(const AlignmentAllocator& other) const { 70 | return true; 71 | } 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "dpf.h" 2 | #include "hashdatastore.h" 3 | 4 | #include 5 | #include 6 | 7 | int main(int argc, char** argv) { 8 | 9 | if(argc != 2) { 10 | std::cout << "Usage: ./dpf_pir " << std::endl; 11 | return -1; 12 | } 13 | size_t NN = std::strtoull(argv[1], nullptr, 10); 14 | std::chrono::duration buildT, evalT, answerT; 15 | size_t keysizeT = 0; 16 | buildT = evalT = answerT = std::chrono::duration::zero(); 17 | for(size_t N = NN; N > 0; N--) { 18 | 19 | hashdatastore store; 20 | store.reserve(1ULL << N); 21 | // Fill Datastore with dummy elements for benchmark 22 | for (size_t i = 0; i < (1ULL << N); i++) { 23 | store.push_back(_mm256_set_epi64x(i, i, i, i)); 24 | } 25 | auto time1 = std::chrono::high_resolution_clock::now(); 26 | auto keys = DPF::Gen(0, N); 27 | auto a = keys.first; 28 | auto b = keys.second; 29 | keysizeT += a.size(); 30 | auto time2 = std::chrono::high_resolution_clock::now(); 31 | 32 | std::vector aaaa; 33 | if(N > 10) { 34 | aaaa = DPF::EvalFull8(a, N); 35 | } else { 36 | aaaa = DPF::EvalFull(a, N); 37 | } 38 | //std::vector bbbb = DPF::EvalFull(b, N); 39 | 40 | auto time3 = std::chrono::high_resolution_clock::now(); 41 | hashdatastore::hash_type answerA = store.answer_pir2(aaaa); 42 | //hashdatastore::hash_type answerB = store.answer_pir2(bbbb); 43 | //hashdatastore::hash_type answer = _mm256_xor_si256(answerA, answerB); 44 | auto time4 = std::chrono::high_resolution_clock::now(); 45 | //std::cout << _mm256_extract_epi64(answer, 0) << std::endl; 46 | 47 | buildT += time2 - time1; 48 | evalT += time3 - time2; 49 | answerT += time4 - time3; 50 | } 51 | std::cout << "DPF.Gen: " << buildT.count() << "sec" << std::endl; 52 | std::cout << "DPF.Eval: " << evalT.count() << "sec" << std::endl; 53 | std::cout << "Inner Prod: " << answerT.count() << "sec" << std::endl; 54 | std::cout << keysizeT << "; " << NN*32 << " bytes total transfer" << std::endl; 55 | 56 | return 0; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /bench.cpp: -------------------------------------------------------------------------------- 1 | #include "dpf.h" 2 | #include "hashdatastore.h" 3 | 4 | #include 5 | #include 6 | 7 | void benchEvalFull(size_t N, size_t iter) { 8 | std::chrono::duration buildT, evalT, answerT; 9 | buildT = evalT = answerT = std::chrono::duration::zero(); 10 | std::cout << "EvalFull, " << iter << " iterations" << std::endl; 11 | auto time1 = std::chrono::high_resolution_clock::now(); 12 | auto keys = DPF::Gen(0, N); 13 | auto a = keys.first; 14 | auto time2 = std::chrono::high_resolution_clock::now(); 15 | for(size_t i = 0; i < iter; i++) { 16 | std::vector aaaa = DPF::EvalFull(a, N); 17 | } 18 | auto time3 = std::chrono::high_resolution_clock::now(); 19 | 20 | buildT += time2 - time1; 21 | evalT += time3 - time2; 22 | std::cout << buildT.count() << "sec" << std::endl; 23 | std::cout << evalT.count() << "sec" << std::endl; 24 | } 25 | 26 | void benchEvalFull8(size_t N, size_t iter) { 27 | std::chrono::duration buildT, evalT, answerT; 28 | buildT = evalT = answerT = std::chrono::duration::zero(); 29 | std::cout << "EvalFull8, " << iter << " iterations" << std::endl; 30 | auto time1 = std::chrono::high_resolution_clock::now(); 31 | auto keys = DPF::Gen(0, N); 32 | auto a = keys.first; 33 | auto time2 = std::chrono::high_resolution_clock::now(); 34 | for(size_t i = 0; i < iter; i++) { 35 | std::vector aaaa = DPF::EvalFull8(a, N); 36 | } 37 | auto time3 = std::chrono::high_resolution_clock::now(); 38 | 39 | buildT += time2 - time1; 40 | evalT += time3 - time2; 41 | std::cout << buildT.count() << "sec" << std::endl; 42 | std::cout << evalT.count() << "sec" << std::endl; 43 | } 44 | 45 | void benchAnswerPIR(size_t N, size_t iter) { 46 | std::array,6> answerT = {std::chrono::duration::zero(), }; 47 | std::cout << "AnswerPIR, " << iter << " iterations" << std::endl; 48 | auto keys = DPF::Gen(0, N); 49 | auto a = keys.first; 50 | hashdatastore store; 51 | store.reserve(1ULL << N); 52 | for (size_t i = 0; i < (1ULL << N); i++) { 53 | store.push_back(_mm256_set_epi64x(i, i, i, i)); 54 | } 55 | std::vector aaaa = DPF::EvalFull8(a, N); 56 | for(size_t i = 0; i < iter; i++) { 57 | auto time0 = std::chrono::high_resolution_clock::now(); 58 | hashdatastore::hash_type answer0 = store.answer_pir_idea_speed_comparison(aaaa); 59 | auto time1 = std::chrono::high_resolution_clock::now(); 60 | hashdatastore::hash_type answer1 = store.answer_pir1(aaaa); 61 | auto time2 = std::chrono::high_resolution_clock::now(); 62 | hashdatastore::hash_type answer2 = store.answer_pir2(aaaa); 63 | auto time3 = std::chrono::high_resolution_clock::now(); 64 | hashdatastore::hash_type answer3 = store.answer_pir3(aaaa); 65 | auto time4 = std::chrono::high_resolution_clock::now(); 66 | hashdatastore::hash_type answer4 = store.answer_pir4(aaaa); 67 | auto time5 = std::chrono::high_resolution_clock::now(); 68 | hashdatastore::hash_type answer5 = store.answer_pir5(aaaa); 69 | auto time6 = std::chrono::high_resolution_clock::now(); 70 | answerT[0] += time1-time0; 71 | answerT[1] += time2-time1; 72 | answerT[2] += time3-time2; 73 | answerT[3] += time4-time3; 74 | answerT[4] += time5-time4; 75 | answerT[5] += time6-time5; 76 | } 77 | 78 | std::cout << "AnswerPIR ideal " << answerT[0].count() << "sec" << std::endl; 79 | std::cout << "AnswerPIR1 " << answerT[1].count() << "sec" << std::endl; 80 | std::cout << "AnswerPIR2 " << answerT[2].count() << "sec" << std::endl; 81 | std::cout << "AnswerPIR3 " << answerT[3].count() << "sec" << std::endl; 82 | std::cout << "AnswerPIR4 " << answerT[4].count() << "sec" << std::endl; 83 | std::cout << "AnswerPIR5 " << answerT[5].count() << "sec" << std::endl; 84 | } 85 | 86 | 87 | int main(int argc, char** argv) { 88 | 89 | size_t N = 27; 90 | size_t iter = 100; 91 | benchEvalFull(N, iter); 92 | benchEvalFull8(N, iter); 93 | benchAnswerPIR(25,100); 94 | 95 | return 0; 96 | 97 | } 98 | -------------------------------------------------------------------------------- /PRNG.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // This file and the associated implementation has been placed in the public domain, waiving all copyright. No restrictions are placed on its use. 3 | #include "Defines.h" 4 | #include "AES.h" 5 | 6 | 7 | #include 8 | #include 9 | 10 | // A Peudorandom number generator implemented using AES-NI. 11 | class PRNG 12 | { 13 | public: 14 | 15 | // default construct leaves the PRNG in an invalid state. 16 | // SetSeed(...) must be called before get(...) 17 | PRNG() = default; 18 | 19 | // explicit constructor to initialize the PRNG with the 20 | // given seed and to buffer bufferSize number of AES block 21 | PRNG(const block& seed, uint64_t bufferSize = 256); 22 | 23 | // standard move constructor. The moved from PRNG is invalide 24 | // unless SetSeed(...) is called. 25 | PRNG(PRNG&& s); 26 | 27 | // Copy is not allowed. 28 | PRNG(const PRNG&) = delete; 29 | 30 | // Set seed from a block and set the desired buffer size. 31 | void SetSeed(const block& b, uint64_t bufferSize = 256); 32 | 33 | // Return the seed for this PRNG. 34 | const block getSeed() const; 35 | 36 | // Templated function that returns the a random element 37 | // of the given type T. 38 | // Required: T must be a POD type. 39 | template 40 | typename std::enable_if::value, T>::type 41 | get() 42 | { 43 | T ret; 44 | get((uint8_t*)&ret, sizeof(T)); 45 | return ret; 46 | } 47 | 48 | // Templated function that fills the provided buffer 49 | // with random elements of the given type T. 50 | // Required: T must be a POD type. 51 | template 52 | typename std::enable_if::value, void>::type 53 | get(T* dest, uint64_t length) 54 | { 55 | uint64_t lengthuint8_t = length * sizeof(T); 56 | uint8_t* destuint8_t = (uint8_t*)dest; 57 | while (lengthuint8_t) 58 | { 59 | uint64_t step = std::min(lengthuint8_t, mBufferByteCapacity - mBytesIdx); 60 | 61 | memcpy(destuint8_t, ((uint8_t*)mBuffer.data()) + mBytesIdx, step); 62 | 63 | destuint8_t += step; 64 | lengthuint8_t -= step; 65 | mBytesIdx += step; 66 | 67 | if (mBytesIdx == mBufferByteCapacity) 68 | refillBuffer(); 69 | } 70 | } 71 | 72 | // Templated function that fills the provided buffer 73 | // with random elements of the given type T. 74 | // Required: T must be a POD type. 75 | template 76 | typename std::enable_if::value, void>::type 77 | get(span dest) 78 | { 79 | get(dest.data(), dest.size()); 80 | } 81 | 82 | // Returns a random element from {0,1} 83 | uint8_t getBit(); 84 | 85 | // STL random number interface 86 | typedef uint32_t result_type; 87 | static result_type min() { return 0; } 88 | static result_type max() { return (result_type)-1; } 89 | result_type operator()() { 90 | return get(); 91 | } 92 | result_type operator()(int mod) { 93 | return get() % mod; 94 | } 95 | 96 | // internal buffer to store future random values. 97 | std::vector mBuffer; 98 | 99 | // AES that generates the randomness by computing AES_seed({0,1,2,...}) 100 | AES mAes; 101 | 102 | // Indicators denoting the current state of the buffer. 103 | uint64_t mBytesIdx = 0, 104 | mBlockIdx = 0, 105 | mBufferByteCapacity = 0; 106 | 107 | // refills the internal buffer with fresh randomness 108 | void refillBuffer(); 109 | 110 | static inline PRNG getTestPRNG() { 111 | PRNG t(TestBlock); 112 | return t; 113 | } 114 | }; 115 | 116 | 117 | // specialization to make bool work correctly. 118 | template<> 119 | inline void PRNG::get(bool* dest, uint64_t length) 120 | { 121 | get((uint8_t*)dest, length); 122 | for (uint64_t i = 0; i < length; ++i) dest[i] = ((uint8_t*)dest)[i] & 1; 123 | } 124 | 125 | // specialization to make bool work correctly. 126 | template<> 127 | inline bool PRNG::get() 128 | { 129 | uint8_t ret; 130 | get((uint8_t*)&ret, 1); 131 | return ret & 1; 132 | } 133 | 134 | 135 | template 136 | typename std::enable_if::value, PRNG&>::type operator<<(T& rhs, PRNG& lhs) 137 | { 138 | lhs.get(&rhs, 1); 139 | } 140 | 141 | -------------------------------------------------------------------------------- /dpf.cpp: -------------------------------------------------------------------------------- 1 | #include "dpf.h" 2 | #include "Defines.h" 3 | #include "PRNG.h" 4 | #include "AES.h" 5 | #include "Log.h" 6 | #include 7 | #include 8 | 9 | namespace DPF { 10 | namespace prg { 11 | inline block getL(const block& seed) { 12 | return mAesFixedKey.encryptECB_MMO(seed); 13 | } 14 | 15 | inline block getR(const block& seed) { 16 | return mAesFixedKey2.encryptECB_MMO(seed); 17 | } 18 | inline std::array getL8(const std::array& seed) { 19 | std::array out; 20 | mAesFixedKey.encryptECB_MMO_Blocks(seed.data(), 8, out.data()); 21 | return out; 22 | } 23 | 24 | inline std::array getR8(const std::array& seed) { 25 | std::array out; 26 | mAesFixedKey2.encryptECB_MMO_Blocks(seed.data(), 8, out.data()); 27 | return out; 28 | } 29 | } 30 | inline block clr(block in) { 31 | return in & ~MSBBlock; 32 | } 33 | inline bool getT(block in) { 34 | return !is_zero(in & MSBBlock); 35 | } 36 | inline void clr8(std::array& in) { 37 | for(int i = 0; i < 8; i++) { 38 | in[i] &= ~MSBBlock; 39 | } 40 | } 41 | inline std::array getT8(const std::array& in) { 42 | std::array out; 43 | for(int i = 0; i < 8; i++) { 44 | out[i] = !is_zero(in[i] & MSBBlock); 45 | } 46 | return out; 47 | } 48 | inline bool ConvertBit(block in) { 49 | return !is_zero(in & LSBBlock); 50 | } 51 | inline block ConvertBlock(block in) { 52 | return mAesFixedKey.encryptECB(in); 53 | } 54 | 55 | inline std::array ConvertBlock8(const std::array& in) { 56 | std::array out; 57 | mAesFixedKey.encryptECBBlocks(in.data(), 8, out.data()); 58 | return out; 59 | } 60 | 61 | std::pair, std::vector> Gen(size_t alpha, size_t logn) { 62 | assert(logn <= 63); 63 | assert(alpha < (1< ka, kb, CW; 65 | PRNG p = PRNG::getTestPRNG(); 66 | block s0, s1; 67 | uint8_t t0, t1; 68 | p.get((uint8_t *) &s0, sizeof(s0)); 69 | p.get((uint8_t *) &s1, sizeof(s1)); 70 | t0 = getT(s0); 71 | t1 = !t0; 72 | 73 | s0 = clr(s0); 74 | s1 = clr(s1); 75 | 76 | ka.insert(ka.end(), (uint8_t*)&s0, ((uint8_t*)&s0) + sizeof(s0)); 77 | ka.push_back(t0); 78 | kb.insert(kb.end(), (uint8_t*)&s1, ((uint8_t*)&s1) + sizeof(s1)); 79 | kb.push_back(t1); 80 | // std::cout << ka.hex() << std::endl; 81 | // std::cout << kb.hex() << std::endl; 82 | size_t stop = logn >=7 ? logn - 7 : 0; // pack 7 layers in final CW 83 | for(size_t i = 0; i < stop; i++) { 84 | Log::v("gen", "%d, %d", t0, t1); 85 | Log::v("gen", s0); 86 | Log::v("gen", s1); 87 | 88 | block s0L = prg::getL(s0); 89 | uint8_t t0L = getT(s0L); 90 | s0L = clr(s0L); 91 | block s0R = prg::getR(s0); 92 | uint8_t t0R = getT(s0R); 93 | s0R = clr(s0R); 94 | 95 | block s1L = prg::getL(s1); 96 | uint8_t t1L = getT(s1L); 97 | s1L = clr(s1L); 98 | block s1R = prg::getR(s1); 99 | uint8_t t1R = getT(s1R); 100 | s1R = clr(s1R); 101 | 102 | if(alpha & (1ULL << (logn-1-i))) { 103 | //KEEP = R, LOSE = L 104 | block scw = s0L ^ s1L; 105 | uint8_t tLCW = t0L ^ t1L; 106 | uint8_t tRCW = t0R ^ t1R ^ 1; 107 | CW.insert(CW.end(), (uint8_t*)&scw, ((uint8_t*)&scw) + sizeof(scw)); 108 | CW.push_back(tLCW); 109 | CW.push_back(tRCW); 110 | 111 | s0 = s0R; 112 | if(t0) s0 = s0 ^ scw; 113 | s1 = s1R; 114 | if(t1) s1 = s1 ^ scw; 115 | // new t 116 | if(t0) t0 = t0R ^ tRCW; 117 | else t0 = t0R; 118 | if(t1) t1 = t1R ^ tRCW; 119 | else t1 = t1R; 120 | } 121 | else { 122 | //KEEP = L, LOSE = R 123 | block scw = s0R ^ s1R; 124 | uint8_t tLCW = t0L ^ t1L ^ 1; 125 | uint8_t tRCW = t0R ^ t1R; 126 | CW.insert(CW.end(), (uint8_t*)&scw, ((uint8_t*)&scw) + sizeof(scw)); 127 | CW.push_back(tLCW); 128 | CW.push_back(tRCW); 129 | //new s 130 | s0 = s0L; 131 | if(t0) s0 = s0 ^ scw; 132 | s1 = s1L; 133 | if(t1) s1 = s1 ^ scw; 134 | // new t 135 | if(t0) t0 = t0L ^ tLCW; 136 | else t0 = t0L; 137 | if(t1) t1 = t1L ^ tLCW; 138 | else t1 = t1L; 139 | } 140 | 141 | } 142 | reg_arr_union tmp = {ZeroBlock}; 143 | tmp.arr[(alpha&127)/8] = (uint8_t)(1U<<((alpha&127)%8)); 144 | tmp.reg = tmp.reg ^ ConvertBlock(s0) ^ ConvertBlock(s1); 145 | CW.insert(CW.end(), (uint8_t*)&tmp.reg, ((uint8_t*)&tmp.reg) + sizeof(tmp.reg)); 146 | ka.insert(ka.end(), CW.begin(), CW.end()); 147 | kb.insert(kb.end(), CW.begin(), CW.end()); 148 | 149 | return std::make_pair(ka, kb); 150 | } 151 | 152 | bool Eval(const std::vector& key, size_t x, size_t logn) { 153 | assert(logn <= 63); 154 | assert(x < (1<=7 ? logn - 7 : 0; // pack 7 layers in final CW 159 | for(size_t i = 0; i < stop; i++) { 160 | Log::v("eval", s); 161 | Log::v("eval", "t: %d", t); 162 | block sL = prg::getL(s); 163 | uint8_t tL = getT(sL); 164 | sL = clr(sL); 165 | block sR = prg::getR(s); 166 | uint8_t tR = getT(sR); 167 | sR = clr(sR); 168 | if(t) { 169 | block sCW; 170 | memcpy(&sCW, key.data() + 17 + i*18, 16); 171 | uint8_t tLCW = key.data()[17+i*18+16]; 172 | uint8_t tRCW = key.data()[17+i*18+17]; 173 | Log::v("eval", "tcw %d %d", tLCW, tRCW); 174 | tL^=tLCW; 175 | tR^=tRCW; 176 | sL^=sCW; 177 | sR^=sCW; 178 | } 179 | if(x & (1ULL<<(logn-1-i))) { 180 | s = sR; 181 | t = tR; 182 | } else { 183 | s = sL; 184 | t = tL; 185 | } 186 | } 187 | Log::v("evalfin", s); 188 | if(t) { 189 | reg_arr_union tmp; 190 | reg_arr_union CW; 191 | memcpy(CW.arr, key.data()+key.size()-16, 16); 192 | tmp.reg = CW.reg ^ ConvertBlock(s); 193 | return (tmp.arr[(x&127)/8] & (1UL << ((x&127)%8))) != 0; 194 | } 195 | else { 196 | reg_arr_union tmp; 197 | tmp.reg = ConvertBlock(s); 198 | return (tmp.arr[(x&127)/8] & (1UL << ((x&127)%8))) != 0; 199 | } 200 | } 201 | 202 | void EvalFullRecursive(const std::vector& key, block s, uint8_t t, size_t lvl, size_t stop, std::vector& res) { 203 | if(lvl == stop) { 204 | if(t) { 205 | reg_arr_union tmp; 206 | reg_arr_union CW; 207 | memcpy(CW.arr, key.data()+key.size()-16, 16); 208 | tmp.reg = CW.reg ^ ConvertBlock(s); 209 | res.insert(res.end(), &tmp.arr[0], &tmp.arr[16]); 210 | } 211 | else { 212 | reg_arr_union tmp; 213 | tmp.reg = ConvertBlock(s); 214 | res.insert(res.end(), &tmp.arr[0], &tmp.arr[16]); 215 | } 216 | return; 217 | } 218 | block sL = prg::getL(s); 219 | uint8_t tL = getT(sL); 220 | sL = clr(sL); 221 | block sR = prg::getR(s); 222 | uint8_t tR = getT(sR); 223 | sR = clr(sR); 224 | if(t) { 225 | block sCW; 226 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 227 | // block* sCW = (block*) key.data() + 17 + lvl*18; 228 | uint8_t tLCW = key.data()[17+lvl*18+16]; 229 | uint8_t tRCW = key.data()[17+lvl*18+17]; 230 | tL^=tLCW; 231 | tR^=tRCW; 232 | sL^=sCW; 233 | sR^=sCW; 234 | } 235 | Log::v("-sL", sL); 236 | EvalFullRecursive(key, sL, tL, lvl+1, stop, res); 237 | Log::v("-sR", sR); 238 | EvalFullRecursive(key, sR, tR, lvl+1, stop, res); 239 | } 240 | 241 | std::vector EvalFull(const std::vector& key, size_t logn) { 242 | assert(logn <= 63); 243 | std::vector data; 244 | if(logn >= 7) 245 | data.reserve(1ULL << (logn-3)); 246 | block s; 247 | memcpy(&s, key.data(), 16); 248 | uint8_t t = key.data()[16]; 249 | size_t stop = logn >=7 ? logn - 7 : 0; // pack 7 layers in final CW 250 | EvalFullRecursive(key, s, t, 0, stop, data); 251 | return data; 252 | } 253 | 254 | // optimized for vectorized ops 255 | void EvalFullRecursive8(const std::vector& key, std::array& s, std::array& t, size_t lvl, size_t stop, std::array& res) { 256 | if(lvl == stop) { 257 | std::array tmp; 258 | reg_arr_union CW; 259 | memcpy(CW.arr, key.data() + key.size() - 16, 16); 260 | std::array conv = ConvertBlock8(s); 261 | for (int i = 0; i < 8; i++) { 262 | block tt = _mm_set1_epi8(-(t[i])); 263 | tmp[i].reg = conv[i] ^ (CW.reg & tt); 264 | memcpy(res[i], tmp[i].arr, 16); 265 | res[i] += sizeof(block); 266 | } 267 | return; 268 | } 269 | std::array sL = prg::getL8(s); 270 | std::array tL = getT8(sL); 271 | clr8(sL); 272 | std::array sR = prg::getR8(s); 273 | std::array tR = getT8(sR); 274 | clr8(sR); 275 | block sCW; 276 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 277 | uint8_t tLCW = key.data()[17+lvl*18+16]; 278 | uint8_t tRCW = key.data()[17+lvl*18+17]; 279 | for(int i = 0; i < 8; i++) { 280 | tL[i] ^= (tLCW & t[i]); 281 | tR[i] ^= (tRCW & t[i]); 282 | block tt = _mm_set1_epi8(-(t[i])); 283 | sL[i] ^= (sCW & tt); 284 | sR[i] ^= (sCW & tt); 285 | } 286 | EvalFullRecursive8(key, sL, tL, lvl+1, stop, res); 287 | EvalFullRecursive8(key, sR, tR, lvl+1, stop, res); 288 | } 289 | 290 | std::vector EvalFull8(const std::vector& key, size_t logn) { 291 | assert(logn <= 63); 292 | std::vector data; 293 | data.resize(1ULL << (logn - 3)); 294 | std::array data_ptrs; 295 | for(size_t i = 0; i < 8; i++) { 296 | data_ptrs[i] = &data[i*(1ULL << (logn - 3 - 3))]; 297 | } 298 | block s; 299 | memcpy(&s, key.data(), 16); 300 | uint8_t t = key.data()[16]; 301 | size_t stop = logn >=7 ? logn - 7 : 0; // pack 7 layers in final CW 302 | assert(stop >= 3); // need 3 or more layers for this to make sense 303 | // evaluate first 3 layers 304 | size_t lvl = 0; 305 | block sL = prg::getL(s); 306 | uint8_t tL = getT(sL); 307 | sL = clr(sL); 308 | block sR = prg::getR(s); 309 | uint8_t tR = getT(sR); 310 | sR = clr(sR); 311 | if(t) { 312 | block sCW; 313 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 314 | uint8_t tLCW = key.data()[17+lvl*18+16]; 315 | uint8_t tRCW = key.data()[17+lvl*18+17]; 316 | tL^=tLCW; 317 | tR^=tRCW; 318 | sL^=sCW; 319 | sR^=sCW; 320 | } 321 | 322 | lvl = 1; 323 | block sLL = prg::getL(sL); 324 | uint8_t tLL = getT(sLL); 325 | sLL = clr(sLL); 326 | block sRL = prg::getR(sL); 327 | uint8_t tRL = getT(sRL); 328 | sRL = clr(sRL); 329 | if(tL) { 330 | block sCW; 331 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 332 | uint8_t tLCW = key.data()[17+lvl*18+16]; 333 | uint8_t tRCW = key.data()[17+lvl*18+17]; 334 | tLL^=tLCW; 335 | tRL^=tRCW; 336 | sLL^=sCW; 337 | sRL^=sCW; 338 | } 339 | block sLR = prg::getL(sR); 340 | uint8_t tLR = getT(sLR); 341 | sLR = clr(sLR); 342 | block sRR = prg::getR(sR); 343 | uint8_t tRR = getT(sRR); 344 | sRR = clr(sRR); 345 | if(tR) { 346 | block sCW; 347 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 348 | uint8_t tLCW = key.data()[17+lvl*18+16]; 349 | uint8_t tRCW = key.data()[17+lvl*18+17]; 350 | tLR^=tLCW; 351 | tRR^=tRCW; 352 | sLR^=sCW; 353 | sRR^=sCW; 354 | } 355 | 356 | lvl = 2; 357 | block sLLL = prg::getL(sLL); 358 | uint8_t tLLL = getT(sLLL); 359 | sLLL = clr(sLLL); 360 | block sRLL = prg::getR(sLL); 361 | uint8_t tRLL = getT(sRLL); 362 | sRLL = clr(sRLL); 363 | if(tLL) { 364 | block sCW; 365 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 366 | uint8_t tLCW = key.data()[17+lvl*18+16]; 367 | uint8_t tRCW = key.data()[17+lvl*18+17]; 368 | tLLL^=tLCW; 369 | tRLL^=tRCW; 370 | sLLL^=sCW; 371 | sRLL^=sCW; 372 | } 373 | block sLRL = prg::getL(sRL); 374 | uint8_t tLRL = getT(sLRL); 375 | sLRL = clr(sLRL); 376 | block sRRL = prg::getR(sRL); 377 | uint8_t tRRL = getT(sRRL); 378 | sRRL = clr(sRRL); 379 | if(tRL) { 380 | block sCW; 381 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 382 | uint8_t tLCW = key.data()[17+lvl*18+16]; 383 | uint8_t tRCW = key.data()[17+lvl*18+17]; 384 | tLRL^=tLCW; 385 | tRRL^=tRCW; 386 | sLRL^=sCW; 387 | sRRL^=sCW; 388 | } 389 | block sLLR = prg::getL(sLR); 390 | uint8_t tLLR = getT(sLLR); 391 | sLLR = clr(sLLR); 392 | block sRLR = prg::getR(sLR); 393 | uint8_t tRLR = getT(sRLR); 394 | sRLR = clr(sRLR); 395 | if(tLR) { 396 | block sCW; 397 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 398 | uint8_t tLCW = key.data()[17+lvl*18+16]; 399 | uint8_t tRCW = key.data()[17+lvl*18+17]; 400 | tLLR^=tLCW; 401 | tRLR^=tRCW; 402 | sLLR^=sCW; 403 | sRLR^=sCW; 404 | } 405 | block sLRR = prg::getL(sRR); 406 | uint8_t tLRR = getT(sLRR); 407 | sLRR = clr(sLRR); 408 | block sRRR = prg::getR(sRR); 409 | uint8_t tRRR = getT(sRRR); 410 | sRRR = clr(sRRR); 411 | if(tRR) { 412 | block sCW; 413 | memcpy(&sCW, key.data() + 17 + lvl*18, 16); 414 | uint8_t tLCW = key.data()[17+lvl*18+16]; 415 | uint8_t tRCW = key.data()[17+lvl*18+17]; 416 | tLRR^=tLCW; 417 | tRRR^=tRCW; 418 | sLRR^=sCW; 419 | sRRR^=sCW; 420 | } 421 | std::array s_array{sLLL, sRLL, sLRL, sRRL, sLLR, sRLR, sLRR, sRRR}; 422 | std::array t_array{tLLL, tRLL, tLRL, tRRL, tLLR, tRLR, tLRR, tRRR}; 423 | 424 | EvalFullRecursive8(key, s_array, t_array, 3, stop, data_ptrs); 425 | return data; 426 | } 427 | 428 | // std::vector EvalFullNonRec(const std::vector& key, size_t logn) { 429 | // assert(logn <= 63); 430 | // std::vector data; 431 | // std::vector sL_vals; 432 | // std::vector sR_vals; 433 | // std::vector tL_vals; 434 | // std::vector tR_vals; 435 | // data.reserve(1ULL << (logn-3)); 436 | // block s; 437 | // memcpy(&s, key.data(), 16); 438 | // uint8_t t = key.data()[16]; 439 | // size_t stop = logn >=7 ? logn - 7 : 0; // pack 7 layers in final CW 440 | // 441 | // for(size_t lvl = 0; lvl < stop; lvl++) { 442 | // const size_t layersize = (1 << lvl); 443 | // block sCW; 444 | // memcpy(&sCW, key.data() + 17 + lvl * 18, 16); 445 | // uint8_t tLCW = key.data()[17 + lvl * 18 + 16]; 446 | // uint8_t tRCW = key.data()[17 + lvl * 18 + 17]; 447 | // for(int j = 0; j < layersize; j++) { 448 | // block sL = prg::getL(s); 449 | // uint8_t tL = getT(sL); 450 | // sL = clr(sL); 451 | // block sR = prg::getR(s); 452 | // uint8_t tR = getT(sR); 453 | // sR = clr(sR); 454 | // if (t) { 455 | // Log::v("eval", "tcw %d %d", tLCW, tRCW); 456 | // tL ^= tLCW; 457 | // tR ^= tRCW; 458 | // sL ^= sCW; 459 | // sR ^= sCW; 460 | // } 461 | // } 462 | // } 463 | // 464 | // if(lvl == stop) { 465 | // if(t) { 466 | // reg_arr_union tmp; 467 | // reg_arr_union CW; 468 | // memcpy(CW.arr, key.data()+key.size()-16, 16); 469 | // tmp.reg = CW.reg ^ ConvertBlock(s); 470 | // res.insert(res.end(), &tmp.arr[0], &tmp.arr[16]); 471 | // } 472 | // else { 473 | // reg_arr_union tmp; 474 | // tmp.reg = ConvertBlock(s); 475 | // res.insert(res.end(), &tmp.arr[0], &tmp.arr[16]); 476 | // } 477 | // return; 478 | // } 479 | // return data; 480 | // } 481 | } 482 | -------------------------------------------------------------------------------- /AES.cpp: -------------------------------------------------------------------------------- 1 | #include "AES.h" 2 | #include 3 | 4 | 5 | const uint8_t fixed_key[16] = {36,156,50,234,92,230,49,9,174,170,205,160,98,236,29,243}; 6 | const AES mAesFixedKey(fixed_key); 7 | const uint8_t fixed_key2[16] = {209, 12, 199, 173, 29, 74, 44, 128, 194, 224, 14, 44, 2, 201, 110, 28}; 8 | const AES mAesFixedKey2(fixed_key2); 9 | 10 | 11 | block keyGenHelper(block key, block keyRcon) 12 | { 13 | keyRcon = _mm_shuffle_epi32(keyRcon, _MM_SHUFFLE(3, 3, 3, 3)); 14 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 15 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 16 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 17 | return _mm_xor_si128(key, keyRcon); 18 | } 19 | 20 | AES::AES() { 21 | uint8_t zerokey[] = {0,0,0,0, 0,0,0,0, 0,0,0,0 , 0,0,0,0}; 22 | setKey(toBlock(zerokey)); 23 | } 24 | 25 | AES::AES(const block& key) { 26 | setKey(key); 27 | } 28 | AES::AES(const uint8_t* key) { 29 | setKey(key); 30 | } 31 | 32 | void AES::setKey(const block& key) { 33 | mRoundKeysEnc[0] = key; 34 | mRoundKeysEnc[1] = keyGenHelper(mRoundKeysEnc[0], _mm_aeskeygenassist_si128(mRoundKeysEnc[0], 0x01)); 35 | mRoundKeysEnc[2] = keyGenHelper(mRoundKeysEnc[1], _mm_aeskeygenassist_si128(mRoundKeysEnc[1], 0x02)); 36 | mRoundKeysEnc[3] = keyGenHelper(mRoundKeysEnc[2], _mm_aeskeygenassist_si128(mRoundKeysEnc[2], 0x04)); 37 | mRoundKeysEnc[4] = keyGenHelper(mRoundKeysEnc[3], _mm_aeskeygenassist_si128(mRoundKeysEnc[3], 0x08)); 38 | mRoundKeysEnc[5] = keyGenHelper(mRoundKeysEnc[4], _mm_aeskeygenassist_si128(mRoundKeysEnc[4], 0x10)); 39 | mRoundKeysEnc[6] = keyGenHelper(mRoundKeysEnc[5], _mm_aeskeygenassist_si128(mRoundKeysEnc[5], 0x20)); 40 | mRoundKeysEnc[7] = keyGenHelper(mRoundKeysEnc[6], _mm_aeskeygenassist_si128(mRoundKeysEnc[6], 0x40)); 41 | mRoundKeysEnc[8] = keyGenHelper(mRoundKeysEnc[7], _mm_aeskeygenassist_si128(mRoundKeysEnc[7], 0x80)); 42 | mRoundKeysEnc[9] = keyGenHelper(mRoundKeysEnc[8], _mm_aeskeygenassist_si128(mRoundKeysEnc[8], 0x1B)); 43 | mRoundKeysEnc[10] = keyGenHelper(mRoundKeysEnc[9], _mm_aeskeygenassist_si128(mRoundKeysEnc[9], 0x36)); 44 | } 45 | 46 | void AES::setKey(const uint8_t* key) { 47 | setKey(toBlock(key)); 48 | } 49 | 50 | void AES::encryptECB(const block& plaintext, block& ciphertext) const { 51 | ciphertext = _mm_xor_si128(plaintext, mRoundKeysEnc[0]); 52 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[1]); 53 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[2]); 54 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[3]); 55 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[4]); 56 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[5]); 57 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[6]); 58 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[7]); 59 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[8]); 60 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[9]); 61 | ciphertext = _mm_aesenclast_si128(ciphertext, mRoundKeysEnc[10]); 62 | } 63 | 64 | void AES::encryptECB_MMO(const block& plaintext, block& ciphertext) const { 65 | ciphertext = _mm_xor_si128(plaintext, mRoundKeysEnc[0]); 66 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[1]); 67 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[2]); 68 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[3]); 69 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[4]); 70 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[5]); 71 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[6]); 72 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[7]); 73 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[8]); 74 | ciphertext = _mm_aesenc_si128(ciphertext, mRoundKeysEnc[9]); 75 | ciphertext = _mm_aesenclast_si128(ciphertext, mRoundKeysEnc[10]); 76 | ciphertext = _mm_xor_si128(ciphertext, plaintext); 77 | } 78 | 79 | void AES::encryptECBBlocks(const block* plaintexts, uint64_t blockLength, block* ciphertexts) const { 80 | 81 | const uint64_t step = 8; 82 | uint64_t idx = 0; 83 | uint64_t length = blockLength - blockLength % step; 84 | 85 | //std::array temp; 86 | block temp[step]; 87 | 88 | for (; idx < length; idx += step) 89 | { 90 | temp[0] = _mm_xor_si128(plaintexts[idx + 0], mRoundKeysEnc[0]); 91 | temp[1] = _mm_xor_si128(plaintexts[idx + 1], mRoundKeysEnc[0]); 92 | temp[2] = _mm_xor_si128(plaintexts[idx + 2], mRoundKeysEnc[0]); 93 | temp[3] = _mm_xor_si128(plaintexts[idx + 3], mRoundKeysEnc[0]); 94 | temp[4] = _mm_xor_si128(plaintexts[idx + 4], mRoundKeysEnc[0]); 95 | temp[5] = _mm_xor_si128(plaintexts[idx + 5], mRoundKeysEnc[0]); 96 | temp[6] = _mm_xor_si128(plaintexts[idx + 6], mRoundKeysEnc[0]); 97 | temp[7] = _mm_xor_si128(plaintexts[idx + 7], mRoundKeysEnc[0]); 98 | 99 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[1]); 100 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[1]); 101 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[1]); 102 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[1]); 103 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[1]); 104 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[1]); 105 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[1]); 106 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[1]); 107 | 108 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[2]); 109 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[2]); 110 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[2]); 111 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[2]); 112 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[2]); 113 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[2]); 114 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[2]); 115 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[2]); 116 | 117 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[3]); 118 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[3]); 119 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[3]); 120 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[3]); 121 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[3]); 122 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[3]); 123 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[3]); 124 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[3]); 125 | 126 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[4]); 127 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[4]); 128 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[4]); 129 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[4]); 130 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[4]); 131 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[4]); 132 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[4]); 133 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[4]); 134 | 135 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[5]); 136 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[5]); 137 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[5]); 138 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[5]); 139 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[5]); 140 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[5]); 141 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[5]); 142 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[5]); 143 | 144 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[6]); 145 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[6]); 146 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[6]); 147 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[6]); 148 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[6]); 149 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[6]); 150 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[6]); 151 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[6]); 152 | 153 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[7]); 154 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[7]); 155 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[7]); 156 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[7]); 157 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[7]); 158 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[7]); 159 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[7]); 160 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[7]); 161 | 162 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[8]); 163 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[8]); 164 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[8]); 165 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[8]); 166 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[8]); 167 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[8]); 168 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[8]); 169 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[8]); 170 | 171 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[9]); 172 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[9]); 173 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[9]); 174 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[9]); 175 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[9]); 176 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[9]); 177 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[9]); 178 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[9]); 179 | 180 | ciphertexts[idx + 0] = _mm_aesenclast_si128(temp[0], mRoundKeysEnc[10]); 181 | ciphertexts[idx + 1] = _mm_aesenclast_si128(temp[1], mRoundKeysEnc[10]); 182 | ciphertexts[idx + 2] = _mm_aesenclast_si128(temp[2], mRoundKeysEnc[10]); 183 | ciphertexts[idx + 3] = _mm_aesenclast_si128(temp[3], mRoundKeysEnc[10]); 184 | ciphertexts[idx + 4] = _mm_aesenclast_si128(temp[4], mRoundKeysEnc[10]); 185 | ciphertexts[idx + 5] = _mm_aesenclast_si128(temp[5], mRoundKeysEnc[10]); 186 | ciphertexts[idx + 6] = _mm_aesenclast_si128(temp[6], mRoundKeysEnc[10]); 187 | ciphertexts[idx + 7] = _mm_aesenclast_si128(temp[7], mRoundKeysEnc[10]); 188 | } 189 | 190 | for (; idx < blockLength; ++idx) 191 | { 192 | ciphertexts[idx] = _mm_xor_si128(plaintexts[idx], mRoundKeysEnc[0]); 193 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[1]); 194 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[2]); 195 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[3]); 196 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[4]); 197 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[5]); 198 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[6]); 199 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[7]); 200 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[8]); 201 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[9]); 202 | ciphertexts[idx] = _mm_aesenclast_si128(ciphertexts[idx], mRoundKeysEnc[10]); 203 | } 204 | } 205 | 206 | void AES::encryptECB_MMO_Blocks(const block* plaintexts, uint64_t blockLength, block* ciphertexts) const { 207 | 208 | const uint64_t step = 8; 209 | uint64_t idx = 0; 210 | uint64_t length = blockLength - blockLength % step; 211 | 212 | //std::array temp; 213 | block temp[step]; 214 | 215 | for (; idx < length; idx += step) 216 | { 217 | temp[0] = _mm_xor_si128(plaintexts[idx + 0], mRoundKeysEnc[0]); 218 | temp[1] = _mm_xor_si128(plaintexts[idx + 1], mRoundKeysEnc[0]); 219 | temp[2] = _mm_xor_si128(plaintexts[idx + 2], mRoundKeysEnc[0]); 220 | temp[3] = _mm_xor_si128(plaintexts[idx + 3], mRoundKeysEnc[0]); 221 | temp[4] = _mm_xor_si128(plaintexts[idx + 4], mRoundKeysEnc[0]); 222 | temp[5] = _mm_xor_si128(plaintexts[idx + 5], mRoundKeysEnc[0]); 223 | temp[6] = _mm_xor_si128(plaintexts[idx + 6], mRoundKeysEnc[0]); 224 | temp[7] = _mm_xor_si128(plaintexts[idx + 7], mRoundKeysEnc[0]); 225 | 226 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[1]); 227 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[1]); 228 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[1]); 229 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[1]); 230 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[1]); 231 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[1]); 232 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[1]); 233 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[1]); 234 | 235 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[2]); 236 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[2]); 237 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[2]); 238 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[2]); 239 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[2]); 240 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[2]); 241 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[2]); 242 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[2]); 243 | 244 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[3]); 245 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[3]); 246 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[3]); 247 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[3]); 248 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[3]); 249 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[3]); 250 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[3]); 251 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[3]); 252 | 253 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[4]); 254 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[4]); 255 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[4]); 256 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[4]); 257 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[4]); 258 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[4]); 259 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[4]); 260 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[4]); 261 | 262 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[5]); 263 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[5]); 264 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[5]); 265 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[5]); 266 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[5]); 267 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[5]); 268 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[5]); 269 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[5]); 270 | 271 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[6]); 272 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[6]); 273 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[6]); 274 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[6]); 275 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[6]); 276 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[6]); 277 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[6]); 278 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[6]); 279 | 280 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[7]); 281 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[7]); 282 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[7]); 283 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[7]); 284 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[7]); 285 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[7]); 286 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[7]); 287 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[7]); 288 | 289 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[8]); 290 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[8]); 291 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[8]); 292 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[8]); 293 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[8]); 294 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[8]); 295 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[8]); 296 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[8]); 297 | 298 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[9]); 299 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[9]); 300 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[9]); 301 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[9]); 302 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[9]); 303 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[9]); 304 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[9]); 305 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[9]); 306 | 307 | temp[0] = _mm_aesenclast_si128(temp[0], mRoundKeysEnc[10]); 308 | temp[1] = _mm_aesenclast_si128(temp[1], mRoundKeysEnc[10]); 309 | temp[2] = _mm_aesenclast_si128(temp[2], mRoundKeysEnc[10]); 310 | temp[3] = _mm_aesenclast_si128(temp[3], mRoundKeysEnc[10]); 311 | temp[4] = _mm_aesenclast_si128(temp[4], mRoundKeysEnc[10]); 312 | temp[5] = _mm_aesenclast_si128(temp[5], mRoundKeysEnc[10]); 313 | temp[6] = _mm_aesenclast_si128(temp[6], mRoundKeysEnc[10]); 314 | temp[7] = _mm_aesenclast_si128(temp[7], mRoundKeysEnc[10]); 315 | 316 | ciphertexts[idx + 0] = _mm_xor_si128(temp[0], plaintexts[0]); 317 | ciphertexts[idx + 1] = _mm_xor_si128(temp[1], plaintexts[1]); 318 | ciphertexts[idx + 2] = _mm_xor_si128(temp[2], plaintexts[2]); 319 | ciphertexts[idx + 3] = _mm_xor_si128(temp[3], plaintexts[3]); 320 | ciphertexts[idx + 4] = _mm_xor_si128(temp[4], plaintexts[4]); 321 | ciphertexts[idx + 5] = _mm_xor_si128(temp[5], plaintexts[5]); 322 | ciphertexts[idx + 6] = _mm_xor_si128(temp[6], plaintexts[6]); 323 | ciphertexts[idx + 7] = _mm_xor_si128(temp[7], plaintexts[7]); 324 | } 325 | 326 | for (; idx < blockLength; ++idx) 327 | { 328 | ciphertexts[idx] = _mm_xor_si128(plaintexts[idx], mRoundKeysEnc[0]); 329 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[1]); 330 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[2]); 331 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[3]); 332 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[4]); 333 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[5]); 334 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[6]); 335 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[7]); 336 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[8]); 337 | ciphertexts[idx] = _mm_aesenc_si128(ciphertexts[idx], mRoundKeysEnc[9]); 338 | ciphertexts[idx] = _mm_aesenclast_si128(ciphertexts[idx], mRoundKeysEnc[10]); 339 | ciphertexts[idx] = _mm_xor_si128(plaintexts[idx], ciphertexts[idx]); 340 | } 341 | } 342 | 343 | void AES::encryptCTR(uint64_t baseIdx, uint64_t blockLength, block * ciphertext) const { 344 | 345 | const uint64_t step = 8; 346 | uint64_t idx = 0; 347 | uint64_t length = blockLength - blockLength % step; 348 | 349 | //std::array temp; 350 | block temp[step]; 351 | 352 | for (; idx < length; idx += step, baseIdx += step) 353 | { 354 | temp[0] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 0), mRoundKeysEnc[0]); 355 | temp[1] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 1), mRoundKeysEnc[0]); 356 | temp[2] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 2), mRoundKeysEnc[0]); 357 | temp[3] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 3), mRoundKeysEnc[0]); 358 | temp[4] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 4), mRoundKeysEnc[0]); 359 | temp[5] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 5), mRoundKeysEnc[0]); 360 | temp[6] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 6), mRoundKeysEnc[0]); 361 | temp[7] = _mm_xor_si128(_mm_set1_epi64x(baseIdx + 7), mRoundKeysEnc[0]); 362 | 363 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[1]); 364 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[1]); 365 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[1]); 366 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[1]); 367 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[1]); 368 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[1]); 369 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[1]); 370 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[1]); 371 | 372 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[2]); 373 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[2]); 374 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[2]); 375 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[2]); 376 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[2]); 377 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[2]); 378 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[2]); 379 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[2]); 380 | 381 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[3]); 382 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[3]); 383 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[3]); 384 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[3]); 385 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[3]); 386 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[3]); 387 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[3]); 388 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[3]); 389 | 390 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[4]); 391 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[4]); 392 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[4]); 393 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[4]); 394 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[4]); 395 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[4]); 396 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[4]); 397 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[4]); 398 | 399 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[5]); 400 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[5]); 401 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[5]); 402 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[5]); 403 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[5]); 404 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[5]); 405 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[5]); 406 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[5]); 407 | 408 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[6]); 409 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[6]); 410 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[6]); 411 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[6]); 412 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[6]); 413 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[6]); 414 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[6]); 415 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[6]); 416 | 417 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[7]); 418 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[7]); 419 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[7]); 420 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[7]); 421 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[7]); 422 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[7]); 423 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[7]); 424 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[7]); 425 | 426 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[8]); 427 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[8]); 428 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[8]); 429 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[8]); 430 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[8]); 431 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[8]); 432 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[8]); 433 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[8]); 434 | 435 | temp[0] = _mm_aesenc_si128(temp[0], mRoundKeysEnc[9]); 436 | temp[1] = _mm_aesenc_si128(temp[1], mRoundKeysEnc[9]); 437 | temp[2] = _mm_aesenc_si128(temp[2], mRoundKeysEnc[9]); 438 | temp[3] = _mm_aesenc_si128(temp[3], mRoundKeysEnc[9]); 439 | temp[4] = _mm_aesenc_si128(temp[4], mRoundKeysEnc[9]); 440 | temp[5] = _mm_aesenc_si128(temp[5], mRoundKeysEnc[9]); 441 | temp[6] = _mm_aesenc_si128(temp[6], mRoundKeysEnc[9]); 442 | temp[7] = _mm_aesenc_si128(temp[7], mRoundKeysEnc[9]); 443 | 444 | ciphertext[idx + 0] = _mm_aesenclast_si128(temp[0], mRoundKeysEnc[10]); 445 | ciphertext[idx + 1] = _mm_aesenclast_si128(temp[1], mRoundKeysEnc[10]); 446 | ciphertext[idx + 2] = _mm_aesenclast_si128(temp[2], mRoundKeysEnc[10]); 447 | ciphertext[idx + 3] = _mm_aesenclast_si128(temp[3], mRoundKeysEnc[10]); 448 | ciphertext[idx + 4] = _mm_aesenclast_si128(temp[4], mRoundKeysEnc[10]); 449 | ciphertext[idx + 5] = _mm_aesenclast_si128(temp[5], mRoundKeysEnc[10]); 450 | ciphertext[idx + 6] = _mm_aesenclast_si128(temp[6], mRoundKeysEnc[10]); 451 | ciphertext[idx + 7] = _mm_aesenclast_si128(temp[7], mRoundKeysEnc[10]); 452 | } 453 | 454 | for (; idx < blockLength; ++idx, ++baseIdx) 455 | { 456 | ciphertext[idx] = _mm_xor_si128(_mm_set1_epi64x(baseIdx), mRoundKeysEnc[0]); 457 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[1]); 458 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[2]); 459 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[3]); 460 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[4]); 461 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[5]); 462 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[6]); 463 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[7]); 464 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[8]); 465 | ciphertext[idx] = _mm_aesenc_si128(ciphertext[idx], mRoundKeysEnc[9]); 466 | ciphertext[idx] = _mm_aesenclast_si128(ciphertext[idx], mRoundKeysEnc[10]); 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /gsl/gsl-lite.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // gsl-lite is based on GSL: Guideline Support Library. 3 | // For more information see https://github.com/martinmoene/gsl-lite 4 | // 5 | // Copyright (c) 2015-2018 Martin Moene 6 | // Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. 7 | // 8 | // This code is licensed under the MIT License (MIT). 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | // THE SOFTWARE. 17 | 18 | #pragma once 19 | 20 | #ifndef GSL_GSL_LITE_HPP_INCLUDED 21 | #define GSL_GSL_LITE_HPP_INCLUDED 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define gsl_lite_VERSION "0.29.0" 34 | 35 | // gsl-lite backward compatibility: 36 | 37 | #ifdef gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR 38 | # define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR 39 | # pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7.0; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).") 40 | #endif 41 | 42 | // M-GSL compatibility: 43 | 44 | #if defined( GSL_THROW_ON_CONTRACT_VIOLATION ) 45 | # define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 1 46 | #endif 47 | 48 | #if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) 49 | # define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 0 50 | #endif 51 | 52 | #if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) 53 | # define gsl_CONFIG_CONTRACT_LEVEL_OFF 1 54 | #endif 55 | 56 | // Configuration: 57 | 58 | #ifndef gsl_FEATURE_HAVE_IMPLICIT_MACRO 59 | # define gsl_FEATURE_HAVE_IMPLICIT_MACRO 1 60 | #endif 61 | 62 | #ifndef gsl_FEATURE_HAVE_OWNER_MACRO 63 | # define gsl_FEATURE_HAVE_OWNER_MACRO 1 64 | #endif 65 | 66 | #ifndef gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 67 | # define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 68 | #endif 69 | 70 | #ifndef gsl_CONFIG_SPAN_INDEX_TYPE 71 | # define gsl_CONFIG_SPAN_INDEX_TYPE size_t 72 | #endif 73 | 74 | #ifndef gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 75 | # define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 76 | #endif 77 | 78 | #ifndef gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 79 | # define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 80 | #endif 81 | 82 | #ifndef gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 83 | # define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 84 | #endif 85 | 86 | #if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) 87 | # define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11 88 | #elif defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) 89 | # define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x00 90 | #elif defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) 91 | # define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x01 92 | #elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) 93 | # define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x10 94 | #else 95 | # define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11 96 | #endif 97 | 98 | #if !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ 99 | !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) 100 | # define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 101 | #elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ 102 | !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) 103 | # define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 1 104 | #elif !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ 105 | defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) 106 | # define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 107 | #else 108 | # error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS and gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES may be defined. 109 | #endif 110 | 111 | // Compiler detection (C++20 is speculative): 112 | // Note: MSVC supports C++14 since it supports C++17. 113 | 114 | #ifdef _MSVC_LANG 115 | # define gsl_MSVC_LANG _MSVC_LANG 116 | #else 117 | # define gsl_MSVC_LANG 0 118 | #endif 119 | 120 | #define gsl_CPP11_OR_GREATER (__cplusplus >= 201103L || gsl_MSVC_LANG >= 201103L ) 121 | #define gsl_CPP14_OR_GREATER (__cplusplus >= 201402L || gsl_MSVC_LANG >= 201703L ) 122 | #define gsl_CPP17_OR_GREATER (__cplusplus >= 201703L || gsl_MSVC_LANG >= 201703L ) 123 | #define gsl_CPP20_OR_GREATER (__cplusplus >= 202000L || gsl_MSVC_LANG >= 202000L ) 124 | 125 | // half-open range [lo..hi): 126 | #define gsl_BETWEEN( v, lo, hi ) ( lo <= v && v < hi ) 127 | 128 | #if defined(_MSC_VER) && !defined(__clang__) 129 | # define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) 130 | #else 131 | # define gsl_COMPILER_MSVC_VERSION 0 132 | # define gsl_COMPILER_NON_MSVC 1 133 | #endif 134 | 135 | // Note: simplistic version computation; works for GCC versions on http://godbolt.org/ 136 | #if defined(__GNUC__) && !defined(__clang__) 137 | # define gsl_COMPILER_GNUC_VERSION ( 10 * (10 *__GNUC__ + __GNUC_MINOR__) + __GNUC_PATCHLEVEL__) 138 | #else 139 | # define gsl_COMPILER_GNUC_VERSION 0 140 | #endif 141 | 142 | // Presence of wide character support: 143 | 144 | #ifdef __DJGPP__ 145 | # define gsl_HAVE_WCHAR 0 146 | #else 147 | # define gsl_HAVE_WCHAR 1 148 | #endif 149 | 150 | // Presence of C++11 language features: 151 | 152 | #define gsl_CPP11_10 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 10) 153 | #define gsl_CPP11_12 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12) 154 | #define gsl_CPP11_14 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14) 155 | 156 | #define gsl_HAVE_AUTO gsl_CPP11_10 157 | #define gsl_HAVE_NULLPTR gsl_CPP11_10 158 | 159 | #define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG gsl_CPP11_12 160 | 161 | #define gsl_HAVE_ALIAS_TEMPLATE gsl_CPP11_14 162 | #define gsl_HAVE_CONSTEXPR_11 gsl_CPP11_14 163 | #define gsl_HAVE_ENUM_CLASS gsl_CPP11_14 164 | #define gsl_HAVE_EXPLICIT_CONVERSION gsl_CPP11_14 165 | #define gsl_HAVE_INITIALIZER_LIST gsl_CPP11_14 166 | #define gsl_HAVE_IS_DEFAULT gsl_CPP11_14 167 | #define gsl_HAVE_IS_DELETE gsl_CPP11_14 168 | #define gsl_HAVE_NOEXCEPT gsl_CPP11_14 169 | 170 | #if gsl_CPP11_OR_GREATER 171 | // see above 172 | #endif 173 | 174 | // Presence of C++14 language features: 175 | 176 | #define gsl_CPP14_00 (gsl_CPP14_OR_GREATER) 177 | #define gsl_CPP14_14 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14) 178 | 179 | #define gsl_HAVE_CONSTEXPR_14 gsl_CPP14_00 180 | #define gsl_HAVE_DECLTYPE_AUTO gsl_CPP14_14 181 | 182 | // Presence of C++17 language features: 183 | 184 | #define gsl_CPP17_00 (gsl_CPP17_OR_GREATER) 185 | #define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE gsl_CPP17_00 186 | 187 | // Presence of C++ library features: 188 | 189 | #ifdef _HAS_CPP0X 190 | # define gsl_HAS_CPP0X _HAS_CPP0X 191 | #else 192 | # define gsl_HAS_CPP0X 0 193 | #endif 194 | 195 | #define gsl_CPP11_LA (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11) 196 | #define gsl_HAVE_ARRAY gsl_CPP11_LA 197 | #define gsl_HAVE_TR1_TYPE_TRAITS gsl_CPP11_LA 198 | 199 | #define gsl_CPP11_LB (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 || (gsl_COMPILER_MSVC_VERSION >= 9 && gsl_HAS_CPP0X)) 200 | #define gsl_HAVE_CONTAINER_DATA_METHOD gsl_CPP11_LB 201 | 202 | #define gsl_CPP11_LC (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14) 203 | #define gsl_HAVE_SIZED_TYPES gsl_CPP11_LC 204 | 205 | #define gsl_CPP11_LD (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 || (gsl_COMPILER_MSVC_VERSION >= 10 && gsl_HAS_CPP0X)) 206 | #define gsl_HAVE_MAKE_SHARED gsl_CPP11_LD 207 | #define gsl_HAVE_SHARED_PTR gsl_CPP11_LD 208 | #define gsl_HAVE_UNIQUE_PTR gsl_CPP11_LD 209 | 210 | #define gsl_CPP14_LA (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12) 211 | #define gsl_HAVE_MAKE_UNIQUE gsl_CPP14_LA 212 | 213 | #define gsl_HAVE_TYPE_TRAITS (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11) 214 | 215 | #define gsl_HAVE_ADD_CONST gsl_HAVE_TYPE_TRAITS 216 | #define gsl_HAVE_INTEGRAL_CONSTANT gsl_HAVE_TYPE_TRAITS 217 | #define gsl_HAVE_REMOVE_CONST gsl_HAVE_TYPE_TRAITS 218 | #define gsl_HAVE_REMOVE_REFERENCE gsl_HAVE_TYPE_TRAITS 219 | 220 | #define gsl_HAVE_TR1_ADD_CONST gsl_HAVE_TR1_TYPE_TRAITS 221 | #define gsl_HAVE_TR1_INTEGRAL_CONSTANT gsl_HAVE_TR1_TYPE_TRAITS 222 | #define gsl_HAVE_TR1_REMOVE_CONST gsl_HAVE_TR1_TYPE_TRAITS 223 | #define gsl_HAVE_TR1_REMOVE_REFERENCE gsl_HAVE_TR1_TYPE_TRAITS 224 | 225 | // For the rest, consider VC12, VC14 as C++11 for GSL Lite. 226 | 227 | // C++ feature usage: 228 | 229 | #if gsl_HAVE_CONSTEXPR_11 230 | # define gsl_constexpr constexpr 231 | #else 232 | # define gsl_constexpr /*constexpr*/ 233 | #endif 234 | 235 | #if gsl_HAVE_CONSTEXPR_14 236 | # define gsl_constexpr14 constexpr 237 | #else 238 | # define gsl_constexpr14 /*constexpr*/ 239 | #endif 240 | 241 | #if gsl_HAVE_EXPLICIT_CONVERSION 242 | # define gsl_explicit explicit 243 | #else 244 | # define gsl_explicit /*explicit*/ 245 | #endif 246 | 247 | #if gsl_FEATURE_HAVE_IMPLICIT_MACRO 248 | # define implicit /*implicit*/ 249 | #endif 250 | 251 | #if gsl_HAVE_IS_DELETE 252 | # define gsl_is_delete = delete 253 | #else 254 | # define gsl_is_delete 255 | #endif 256 | 257 | #if gsl_HAVE_IS_DELETE 258 | # define gsl_is_delete_access public 259 | #else 260 | # define gsl_is_delete_access private 261 | #endif 262 | 263 | #if !gsl_HAVE_NOEXCEPT || gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 264 | # define gsl_noexcept /*noexcept*/ 265 | #else 266 | # define gsl_noexcept noexcept 267 | #endif 268 | 269 | #if gsl_HAVE_NULLPTR 270 | # define gsl_nullptr nullptr 271 | #else 272 | # define gsl_nullptr NULL 273 | #endif 274 | 275 | #define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) 276 | 277 | // Other features: 278 | 279 | #define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR \ 280 | ( gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD ) 281 | 282 | // Note: !defined(__NVCC__) doesn't work with nvcc here: 283 | #define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR \ 284 | ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && (__NVCC__== 0) ) 285 | 286 | // GSL API (e.g. for CUDA platform): 287 | 288 | #ifndef gsl_api 289 | # ifdef __CUDACC__ 290 | # define gsl_api __host__ __device__ 291 | # else 292 | # define gsl_api /*gsl_api*/ 293 | # endif 294 | #endif 295 | 296 | // Additional includes: 297 | 298 | #if gsl_HAVE_ARRAY 299 | # include 300 | #endif 301 | 302 | #if gsl_HAVE_TYPE_TRAITS 303 | # include 304 | #elif gsl_HAVE_TR1_TYPE_TRAITS 305 | # include 306 | #endif 307 | 308 | #if gsl_HAVE_SIZED_TYPES 309 | # include 310 | #endif 311 | 312 | // MSVC warning suppression macros: 313 | 314 | #if gsl_COMPILER_MSVC_VERSION >= 14 315 | # define gsl_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] 316 | # define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) 317 | # define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) 318 | # define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop )) 319 | #else 320 | # define gsl_SUPPRESS_MSGSL_WARNING(expr) 321 | # define gsl_SUPPRESS_MSVC_WARNING(code, descr) 322 | # define gsl_DISABLE_MSVC_WARNINGS(codes) 323 | # define gsl_RESTORE_MSVC_WARNINGS() 324 | #endif 325 | 326 | // Suppress the following MSVC GSL warnings: 327 | // - C26410: gsl::r.32: the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead 328 | // - C26415: gsl::r.30: smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead 329 | // - C26418: gsl::r.36: shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead 330 | // - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions; 331 | // use brace initialization, gsl::narrow_cast or gsl::narow 332 | // - C26439, gsl::f.6 : special function 'function' can be declared 'noexcept' 333 | // - C26440, gsl::f.6 : function 'function' can be declared 'noexcept' 334 | // - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same 335 | // - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead 336 | // - C26482, gsl::b.2 : only index into arrays using constant expressions 337 | // - C26490: gsl::t.1 : don't use reinterpret_cast 338 | 339 | gsl_DISABLE_MSVC_WARNINGS( 26410 26415 26418 26472 26439 26440 26473 26481 26482 26490 ) 340 | 341 | namespace gsl { 342 | 343 | namespace detail { 344 | 345 | // C++11 emulation: 346 | 347 | #if gsl_HAVE_ADD_CONST 348 | 349 | using std::add_const; 350 | 351 | #elif gsl_HAVE_TR1_ADD_CONST 352 | 353 | using std::tr1::add_const; 354 | 355 | #else 356 | 357 | template< class T > struct add_const { typedef const T type; }; 358 | 359 | #endif // gsl_HAVE_ADD_CONST 360 | 361 | #if gsl_HAVE_REMOVE_CONST 362 | 363 | using std::remove_cv; 364 | using std::remove_const; 365 | using std::remove_volatile; 366 | 367 | #elif gsl_HAVE_TR1_REMOVE_CONST 368 | 369 | using std::tr1::remove_cv; 370 | using std::tr1::remove_const; 371 | using std::tr1::remove_volatile; 372 | 373 | #else 374 | 375 | template< class T > struct remove_const { typedef T type; }; 376 | template< class T > struct remove_const { typedef T type; }; 377 | 378 | template< class T > struct remove_volatile { typedef T type; }; 379 | template< class T > struct remove_volatile { typedef T type; }; 380 | 381 | template< class T > 382 | struct remove_cv 383 | { 384 | typedef typename detail::remove_volatile::type>::type type; 385 | }; 386 | 387 | #endif // gsl_HAVE_REMOVE_CONST 388 | 389 | #if gsl_HAVE_INTEGRAL_CONSTANT 390 | 391 | using std::integral_constant; 392 | using std::true_type; 393 | using std::false_type; 394 | 395 | #elif gsl_HAVE_TR1_INTEGRAL_CONSTANT 396 | 397 | using std::tr1::integral_constant; 398 | using std::tr1::true_type; 399 | using std::tr1::false_type; 400 | 401 | #else 402 | 403 | template< int v > struct integral_constant { enum { value = v }; }; 404 | typedef integral_constant< true > true_type; 405 | typedef integral_constant< false > false_type; 406 | 407 | #endif 408 | 409 | #if gsl_HAVE_ARRAY 410 | 411 | template< class T > 412 | struct is_std_array_oracle : false_type {}; 413 | 414 | template< class T, std::size_t N > 415 | struct is_std_array_oracle< std::array > : true_type {}; 416 | 417 | template< class T > 418 | struct is_std_array : is_std_array_oracle< typename remove_cv::type > {}; 419 | 420 | #endif 421 | 422 | } // namespace detail 423 | 424 | // 425 | // GSL.util: utilities 426 | // 427 | 428 | // index type for all container indexes/subscripts/sizes 429 | typedef gsl_CONFIG_SPAN_INDEX_TYPE index; // p0122r3 uses std::ptrdiff_t 430 | 431 | // 432 | // GSL.owner: ownership pointers 433 | // 434 | #if gsl_HAVE_SHARED_PTR 435 | using std::unique_ptr; 436 | using std::shared_ptr; 437 | using std::make_shared; 438 | # if gsl_HAVE_MAKE_UNIQUE 439 | using std::make_unique; 440 | # endif 441 | #endif 442 | 443 | #if gsl_HAVE_ALIAS_TEMPLATE 444 | # if gsl_HAVE_TYPE_TRAITS 445 | template< class T, class = typename std::enable_if< std::is_pointer::value >::type > 446 | using owner = T; 447 | # else 448 | template< class T > using owner = T; 449 | # endif 450 | #else 451 | template< class T > struct owner { typedef T type; }; 452 | #endif 453 | 454 | #define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE 455 | 456 | #if gsl_FEATURE_HAVE_OWNER_MACRO 457 | # if gsl_HAVE_OWNER_TEMPLATE 458 | # define Owner(t) ::gsl::owner 459 | # else 460 | # define Owner(t) ::gsl::owner::type 461 | # endif 462 | #endif 463 | 464 | // 465 | // GSL.assert: assertions 466 | // 467 | 468 | #define gsl_ELIDE_CONTRACT_EXPECTS ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x01 ) ) 469 | #define gsl_ELIDE_CONTRACT_ENSURES ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x10 ) ) 470 | 471 | #if gsl_ELIDE_CONTRACT_EXPECTS 472 | # define Expects( x ) /* Expects elided */ 473 | #elif gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 474 | # define Expects( x ) ::gsl::fail_fast_assert( (x), "GSL: Precondition failure at " __FILE__ ": " gsl_STRINGIFY(__LINE__) ); 475 | #else 476 | # define Expects( x ) ::gsl::fail_fast_assert( (x) ) 477 | #endif 478 | 479 | #if gsl_ELIDE_CONTRACT_ENSURES 480 | # define Ensures( x ) /* Ensures elided */ 481 | #elif gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 482 | # define Ensures( x ) ::gsl::fail_fast_assert( (x), "GSL: Postcondition failure at " __FILE__ ": " gsl_STRINGIFY(__LINE__) ); 483 | #else 484 | # define Ensures( x ) ::gsl::fail_fast_assert( (x) ) 485 | #endif 486 | 487 | #define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) 488 | #define gsl_STRINGIFY_( x ) #x 489 | 490 | struct fail_fast : public std::logic_error 491 | { 492 | gsl_api explicit fail_fast( char const * const message ) 493 | : std::logic_error( message ) {} 494 | }; 495 | 496 | // workaround for gcc 5 throw/terminate constexpr bug: 497 | 498 | #if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600 ) && gsl_HAVE_CONSTEXPR_14 499 | 500 | # if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 501 | 502 | gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond, char const * const message ) -> void 503 | { 504 | !cond ? throw fail_fast( message ) : 0; 505 | } 506 | 507 | # else 508 | 509 | gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond ) -> void 510 | { 511 | struct F { static gsl_constexpr14 void f(){}; }; 512 | 513 | !cond ? std::terminate() : F::f(); 514 | } 515 | 516 | # endif 517 | 518 | #else // workaround 519 | 520 | # if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 521 | 522 | gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond, char const * const message ) 523 | { 524 | if ( !cond ) 525 | throw fail_fast( message ); 526 | } 527 | 528 | # else 529 | 530 | gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond ) gsl_noexcept 531 | { 532 | if ( !cond ) 533 | std::terminate(); 534 | } 535 | 536 | # endif 537 | #endif // workaround 538 | 539 | // 540 | // GSL.util: utilities 541 | // 542 | 543 | #if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11 544 | 545 | template< class F > 546 | class final_action 547 | { 548 | public: 549 | gsl_api explicit final_action( F action ) gsl_noexcept 550 | : action_( std::move( action ) ) 551 | , invoke_( true ) 552 | {} 553 | 554 | gsl_api final_action( final_action && other ) gsl_noexcept 555 | : action_( std::move( other.action_ ) ) 556 | , invoke_( other.invoke_ ) 557 | { 558 | other.invoke_ = false; 559 | } 560 | 561 | gsl_api virtual ~final_action() gsl_noexcept 562 | { 563 | if ( invoke_ ) 564 | action_(); 565 | } 566 | 567 | gsl_is_delete_access: 568 | gsl_api final_action( final_action const & ) gsl_is_delete; 569 | gsl_api final_action & operator=( final_action const & ) gsl_is_delete; 570 | gsl_api final_action & operator=( final_action && ) gsl_is_delete; 571 | 572 | protected: 573 | gsl_api void dismiss() gsl_noexcept 574 | { 575 | invoke_ = false; 576 | } 577 | 578 | #if gsl_CPP17_OR_GREATER 579 | gsl_api int uncaught_exceptions() gsl_noexcept 580 | { 581 | return std::uncaught_exceptions(); 582 | } 583 | #else 584 | gsl_api int uncaught_exceptions() 585 | { 586 | return std::uncaught_exception() ? 1 : 0; 587 | } 588 | #endif 589 | 590 | private: 591 | F action_; 592 | bool invoke_; 593 | }; 594 | 595 | template< class F > 596 | gsl_api inline final_action finally( F const & action ) gsl_noexcept 597 | { 598 | return final_action( action ); 599 | } 600 | 601 | template< class F > 602 | gsl_api inline final_action finally( F && action ) gsl_noexcept 603 | { 604 | return final_action( std::forward( action ) ); 605 | } 606 | 607 | #if gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 608 | 609 | template< class F > 610 | class final_action_return : public final_action 611 | { 612 | public: 613 | gsl_api explicit final_action_return( F && action ) gsl_noexcept 614 | : final_action( std::move( action ) ) 615 | {} 616 | 617 | gsl_api final_action_return( final_action_return && other ) gsl_noexcept 618 | : final_action( std::move( other ) ) 619 | {} 620 | 621 | gsl_api ~final_action_return() override 622 | { 623 | if ( this->uncaught_exceptions() ) 624 | this->dismiss(); 625 | } 626 | 627 | gsl_is_delete_access: 628 | gsl_api final_action_return( final_action_return const & ) gsl_is_delete; 629 | gsl_api final_action_return & operator=( final_action_return const & ) gsl_is_delete; 630 | }; 631 | 632 | template< class F > 633 | gsl_api inline final_action_return on_return( F const & action ) gsl_noexcept 634 | { 635 | return final_action_return( action ); 636 | } 637 | 638 | template< class F > 639 | gsl_api inline final_action_return on_return( F && action ) gsl_noexcept 640 | { 641 | return final_action_return( std::forward( action ) ); 642 | } 643 | 644 | template< class F > 645 | class final_action_error : public final_action 646 | { 647 | public: 648 | gsl_api explicit final_action_error( F && action ) gsl_noexcept 649 | : final_action( std::move( action ) ) 650 | {} 651 | 652 | gsl_api final_action_error( final_action_error && other ) gsl_noexcept 653 | : final_action( std::move( other ) ) 654 | {} 655 | 656 | gsl_api ~final_action_error() override 657 | { 658 | if ( ! this->uncaught_exceptions() ) 659 | this->dismiss(); 660 | } 661 | 662 | gsl_is_delete_access: 663 | gsl_api final_action_error( final_action_error const & ) gsl_is_delete; 664 | gsl_api final_action_error & operator=( final_action_error const & ) gsl_is_delete; 665 | }; 666 | 667 | template< class F > 668 | gsl_api inline final_action_error on_error( F const & action ) gsl_noexcept 669 | { 670 | return final_action_error( action ); 671 | } 672 | 673 | template< class F > 674 | gsl_api inline final_action_error on_error( F && action ) gsl_noexcept 675 | { 676 | return final_action_error( std::forward( action ) ); 677 | } 678 | 679 | #endif // gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 680 | 681 | #else // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11 682 | 683 | class final_action 684 | { 685 | public: 686 | typedef void (*Action)(); 687 | 688 | gsl_api final_action( Action action ) 689 | : action_( action ) 690 | , invoke_( true ) 691 | {} 692 | 693 | gsl_api final_action( final_action const & other ) 694 | : action_( other.action_ ) 695 | , invoke_( other.invoke_ ) 696 | { 697 | other.invoke_ = false; 698 | } 699 | 700 | gsl_api virtual ~final_action() 701 | { 702 | if ( invoke_ ) 703 | action_(); 704 | } 705 | 706 | protected: 707 | gsl_api void dismiss() 708 | { 709 | invoke_ = false; 710 | } 711 | 712 | gsl_api int uncaught_exceptions() 713 | { 714 | return std::uncaught_exception() ? 1 : 0; 715 | } 716 | 717 | private: 718 | gsl_api final_action & operator=( final_action const & ); 719 | 720 | private: 721 | Action action_; 722 | mutable bool invoke_; 723 | }; 724 | 725 | template< class F > 726 | gsl_api inline final_action finally( F const & f ) 727 | { 728 | return final_action(( f )); 729 | } 730 | 731 | #if gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 732 | 733 | class final_action_return : public final_action 734 | { 735 | public: 736 | gsl_api explicit final_action_return( Action action ) 737 | : final_action( action ) 738 | {} 739 | 740 | gsl_api ~final_action_return() 741 | { 742 | if ( this->uncaught_exceptions() ) 743 | this->dismiss(); 744 | } 745 | 746 | private: 747 | gsl_api final_action_return & operator=( final_action_return const & ); 748 | }; 749 | 750 | template< class F > 751 | gsl_api inline final_action_return on_return( F const & action ) 752 | { 753 | return final_action_return( action ); 754 | } 755 | 756 | class final_action_error : public final_action 757 | { 758 | public: 759 | gsl_api explicit final_action_error( Action action ) 760 | : final_action( action ) 761 | {} 762 | 763 | gsl_api ~final_action_error() 764 | { 765 | if ( ! this->uncaught_exceptions() ) 766 | this->dismiss(); 767 | } 768 | 769 | private: 770 | gsl_api final_action_error & operator=( final_action_error const & ); 771 | }; 772 | 773 | template< class F > 774 | gsl_api inline final_action_error on_error( F const & action ) 775 | { 776 | return final_action_error( action ); 777 | } 778 | 779 | #endif // gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 780 | 781 | #endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11 782 | 783 | #if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12 784 | 785 | template< class T, class U > 786 | gsl_api inline gsl_constexpr T narrow_cast( U && u ) gsl_noexcept 787 | { 788 | return static_cast( std::forward( u ) ); 789 | } 790 | 791 | #else 792 | 793 | template< class T, class U > 794 | gsl_api inline T narrow_cast( U u ) gsl_noexcept 795 | { 796 | return static_cast( u ); 797 | } 798 | 799 | #endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12 800 | 801 | struct narrowing_error : public std::exception {}; 802 | 803 | #if gsl_HAVE_TYPE_TRAITS 804 | 805 | namespace details 806 | { 807 | template< class T, class U > 808 | struct is_same_signedness : public std::integral_constant::value == std::is_signed::value> 809 | {}; 810 | } 811 | #endif 812 | 813 | template< class T, class U > 814 | gsl_api inline T narrow( U u ) 815 | { 816 | T t = narrow_cast( u ); 817 | 818 | if ( static_cast( t ) != u ) 819 | { 820 | #if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 821 | throw narrowing_error(); 822 | #else 823 | std::terminate(); 824 | #endif 825 | } 826 | 827 | #if gsl_HAVE_TYPE_TRAITS 828 | if ( ! details::is_same_signedness::value && ( ( t < T() ) != ( u < U() ) ) ) 829 | #else 830 | // Don't assume T() works: 831 | if ( ( t < 0 ) != ( u < 0 ) ) 832 | #endif 833 | { 834 | #if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 835 | throw narrowing_error(); 836 | #else 837 | std::terminate(); 838 | #endif 839 | } 840 | return t; 841 | } 842 | 843 | // 844 | // at() - Bounds-checked way of accessing static arrays, std::array, std::vector. 845 | // 846 | 847 | template< class T, size_t N > 848 | gsl_api inline gsl_constexpr14 T & at( T(&arr)[N], size_t index ) 849 | { 850 | Expects( index < N ); 851 | return arr[index]; 852 | } 853 | 854 | #if gsl_HAVE_ARRAY 855 | 856 | template< class T, size_t N > 857 | gsl_api inline gsl_constexpr14 T & at( std::array & arr, size_t index ) 858 | { 859 | Expects( index < N ); 860 | return arr[index]; 861 | } 862 | #endif 863 | 864 | template< class Cont > 865 | gsl_api inline gsl_constexpr14 typename Cont::value_type & at( Cont & cont, size_t index ) 866 | { 867 | Expects( index < cont.size() ); 868 | return cont[index]; 869 | } 870 | 871 | #if gsl_HAVE_INITIALIZER_LIST 872 | 873 | template< class T > 874 | gsl_api inline const gsl_constexpr14 T & at( std::initializer_list cont, size_t index ) 875 | { 876 | Expects( index < cont.size() ); 877 | return *( cont.begin() + index ); 878 | } 879 | #endif 880 | 881 | template< class T > 882 | class span; 883 | 884 | template< class T > 885 | gsl_api inline gsl_constexpr14 T & at( span s, size_t index ) 886 | { 887 | return s.at( index ); 888 | } 889 | 890 | // 891 | // GSL.views: views 892 | // 893 | 894 | // 895 | // not_null<> - Wrap any indirection and enforce non-null. 896 | // 897 | template< class T > 898 | class not_null 899 | { 900 | public: 901 | gsl_api gsl_constexpr14 not_null( T t ) : ptr_ ( t ){ Expects( ptr_ != gsl_nullptr ); } 902 | gsl_api not_null & operator=( T t ) { ptr_ = t ; Expects( ptr_ != gsl_nullptr ); return *this; } 903 | 904 | #if gsl_HAVE_IS_DEFAULT 905 | gsl_api gsl_constexpr not_null( not_null const & other ) = default; 906 | gsl_api gsl_constexpr not_null( not_null && other ) = default; 907 | gsl_api ~not_null() = default; 908 | gsl_api not_null & operator=( not_null const & other ) = default; 909 | gsl_api not_null & operator=( not_null && other ) = default; 910 | #else 911 | gsl_api gsl_constexpr not_null( not_null const & other ) : ptr_ ( other.ptr_ ) {} 912 | gsl_api ~not_null() {}; 913 | gsl_api not_null & operator=( not_null const & other ) { ptr_ = other.ptr_; return *this; } 914 | #endif 915 | 916 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 917 | 918 | template< class U, class Dummy = typename std::enable_if::value, void>::type > 919 | gsl_api gsl_constexpr not_null( not_null const & other ) 920 | : ptr_( other.get() ) 921 | {} 922 | 923 | template< class U, class Dummy = typename std::enable_if::value, void>::type > 924 | gsl_api not_null & operator=( not_null const & other ) 925 | { 926 | ptr_ = other.get(); 927 | return *this; 928 | } 929 | #else 930 | template< class U > 931 | gsl_api gsl_constexpr not_null( not_null const & other ) 932 | : ptr_( other.get() ) 933 | {} 934 | 935 | template< class U > 936 | gsl_api gsl_constexpr not_null & operator=( not_null const & other ) 937 | { 938 | ptr_ = other.get(); 939 | return *this; 940 | } 941 | #endif 942 | 943 | gsl_api gsl_constexpr14 T get() const 944 | { 945 | Ensures( ptr_ != gsl_nullptr ); 946 | return ptr_; 947 | } 948 | 949 | gsl_api gsl_constexpr operator T() const { return get(); } 950 | gsl_api gsl_constexpr T operator->() const { return get(); } 951 | 952 | #if gsl_HAVE_DECLTYPE_AUTO 953 | gsl_api gsl_constexpr decltype(auto) operator*() const { return *get(); } 954 | #endif 955 | 956 | gsl_is_delete_access: 957 | // prevent compilation when initialized with a nullptr or literal 0: 958 | #if gsl_HAVE_NULLPTR 959 | gsl_api not_null( std::nullptr_t ) gsl_is_delete; 960 | gsl_api not_null & operator=( std::nullptr_t ) gsl_is_delete; 961 | #else 962 | gsl_api not_null( int ) gsl_is_delete; 963 | gsl_api not_null & operator=( int ) gsl_is_delete; 964 | #endif 965 | 966 | // unwanted operators...pointers only point to single objects! 967 | gsl_api not_null & operator++() gsl_is_delete; 968 | gsl_api not_null & operator--() gsl_is_delete; 969 | gsl_api not_null operator++( int ) gsl_is_delete; 970 | gsl_api not_null operator--( int ) gsl_is_delete; 971 | gsl_api not_null & operator+ ( size_t ) gsl_is_delete; 972 | gsl_api not_null & operator+=( size_t ) gsl_is_delete; 973 | gsl_api not_null & operator- ( size_t ) gsl_is_delete; 974 | gsl_api not_null & operator-=( size_t ) gsl_is_delete; 975 | gsl_api not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; 976 | gsl_api not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; 977 | gsl_api void operator[]( std::ptrdiff_t ) const gsl_is_delete; 978 | 979 | private: 980 | T ptr_; 981 | }; 982 | 983 | // more not_null unwanted operators 984 | 985 | template< class T, class U > 986 | std::ptrdiff_t operator-( not_null const &, not_null const & ) gsl_is_delete; 987 | 988 | template< class T > 989 | not_null operator-( not_null const &, std::ptrdiff_t ) gsl_is_delete; 990 | 991 | template< class T > 992 | not_null operator+( not_null const &, std::ptrdiff_t ) gsl_is_delete; 993 | 994 | template< class T > 995 | not_null operator+( std::ptrdiff_t, not_null const & ) gsl_is_delete; 996 | 997 | 998 | // not_null comparisons 999 | 1000 | template< class T, class U > 1001 | gsl_api inline gsl_constexpr14 bool operator==( not_null const & l, not_null const & r ) 1002 | { 1003 | return l.get() == r.get(); 1004 | } 1005 | 1006 | template< class T, class U > 1007 | gsl_api inline gsl_constexpr14 bool operator< ( not_null const & l, not_null const & r ) 1008 | { 1009 | return l.get() < r.get(); 1010 | } 1011 | 1012 | template< class T, class U > 1013 | gsl_api inline gsl_constexpr14 bool operator!=( not_null const & l, not_null const & r ) 1014 | { 1015 | return !( l == r ); 1016 | } 1017 | 1018 | template< class T, class U > 1019 | gsl_api inline gsl_constexpr14 bool operator<=( not_null const & l, not_null const & r ) 1020 | { 1021 | return !( r < l ); 1022 | } 1023 | 1024 | template< class T, class U > 1025 | gsl_api inline gsl_constexpr14 bool operator> ( not_null const & l, not_null const & r ) 1026 | { 1027 | return ( r < l ); 1028 | } 1029 | 1030 | template< class T, class U > 1031 | gsl_api inline gsl_constexpr14 bool operator>=( not_null const & l, not_null const & r ) 1032 | { 1033 | return !( l < r ); 1034 | } 1035 | 1036 | // 1037 | // Byte-specific type. 1038 | // 1039 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1040 | enum class byte : unsigned char {}; 1041 | #else 1042 | struct byte { typedef unsigned char type; type v; }; 1043 | #endif 1044 | 1045 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1046 | # define gsl_ENABLE_IF_INTEGRAL_T(T) \ 1047 | , class = typename std::enable_if::value>::type 1048 | #else 1049 | # define gsl_ENABLE_IF_INTEGRAL_T(T) 1050 | #endif 1051 | 1052 | template< class T > 1053 | gsl_api inline gsl_constexpr byte to_byte( T v ) gsl_noexcept 1054 | { 1055 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1056 | return static_cast( v ); 1057 | #elif gsl_HAVE_CONSTEXPR_11 1058 | return { static_cast( v ) }; 1059 | #else 1060 | byte b = { static_cast( v ) }; return b; 1061 | #endif 1062 | } 1063 | 1064 | template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > 1065 | gsl_api inline gsl_constexpr IntegerType to_integer( byte b ) gsl_noexcept 1066 | { 1067 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1068 | return static_cast::type>( b ); 1069 | #else 1070 | return b.v; 1071 | #endif 1072 | } 1073 | 1074 | gsl_api inline gsl_constexpr unsigned char to_uchar( byte b ) gsl_noexcept 1075 | { 1076 | return to_integer( b ); 1077 | } 1078 | 1079 | gsl_api inline gsl_constexpr unsigned char to_uchar( int i ) gsl_noexcept 1080 | { 1081 | return static_cast( i ); 1082 | } 1083 | 1084 | #if ! gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1085 | 1086 | gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept 1087 | { 1088 | return l.v == r.v; 1089 | } 1090 | 1091 | gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept 1092 | { 1093 | return !( l == r ); 1094 | } 1095 | 1096 | gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept 1097 | { 1098 | return l.v < r.v; 1099 | } 1100 | 1101 | gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept 1102 | { 1103 | return !( r < l ); 1104 | } 1105 | 1106 | gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept 1107 | { 1108 | return ( r < l ); 1109 | } 1110 | 1111 | gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept 1112 | { 1113 | return !( l < r ); 1114 | } 1115 | #endif 1116 | 1117 | template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > 1118 | gsl_api inline gsl_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) gsl_noexcept 1119 | { 1120 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1121 | return b = to_byte( to_uchar( b ) << shift ); 1122 | #else 1123 | b.v = to_uchar( b.v << shift ); return b; 1124 | #endif 1125 | } 1126 | 1127 | template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > 1128 | gsl_api inline gsl_constexpr byte operator<<( byte b, IntegerType shift ) gsl_noexcept 1129 | { 1130 | return to_byte( to_uchar( b ) << shift ); 1131 | } 1132 | 1133 | template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > 1134 | gsl_api inline gsl_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) gsl_noexcept 1135 | { 1136 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1137 | return b = to_byte( to_uchar( b ) >> shift ); 1138 | #else 1139 | b.v = to_uchar( b.v >> shift ); return b; 1140 | #endif 1141 | } 1142 | 1143 | template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > 1144 | gsl_api inline gsl_constexpr byte operator>>( byte b, IntegerType shift ) gsl_noexcept 1145 | { 1146 | return to_byte( to_uchar( b ) >> shift ); 1147 | } 1148 | 1149 | gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept 1150 | { 1151 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1152 | return l = to_byte( to_uchar( l ) | to_uchar( r ) ); 1153 | #else 1154 | l.v = to_uchar( l ) | to_uchar( r ); return l; 1155 | #endif 1156 | } 1157 | 1158 | gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept 1159 | { 1160 | return to_byte( to_uchar( l ) | to_uchar( r ) ); 1161 | } 1162 | 1163 | gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept 1164 | { 1165 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1166 | return l = to_byte( to_uchar( l ) & to_uchar( r ) ); 1167 | #else 1168 | l.v = to_uchar( l ) & to_uchar( r ); return l; 1169 | #endif 1170 | } 1171 | 1172 | gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept 1173 | { 1174 | return to_byte( to_uchar( l ) & to_uchar( r ) ); 1175 | } 1176 | 1177 | gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept 1178 | { 1179 | #if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1180 | return l = to_byte( to_uchar( l ) ^ to_uchar (r ) ); 1181 | #else 1182 | l.v = to_uchar( l ) ^ to_uchar (r ); return l; 1183 | #endif 1184 | } 1185 | 1186 | gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept 1187 | { 1188 | return to_byte( to_uchar( l ) ^ to_uchar( r ) ); 1189 | } 1190 | 1191 | gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept 1192 | { 1193 | return to_byte( ~to_uchar( b ) ); 1194 | } 1195 | 1196 | // tag to select span constructor taking a container (prevent ms-gsl warning C26426): 1197 | 1198 | #if gsl_CPP14_OR_GREATER 1199 | struct with_container_t{ constexpr with_container_t() noexcept {} }; 1200 | const with_container_t with_container; 1201 | #else 1202 | struct with_container_t{ with_container_t(){} }; 1203 | const with_container_t with_container; 1204 | #endif 1205 | 1206 | // 1207 | // span<> - A 1D view of contiguous T's, replace (*,len). 1208 | // 1209 | template< class T > 1210 | class span 1211 | { 1212 | template< class U > friend class span; 1213 | 1214 | public: 1215 | typedef index index_type; 1216 | 1217 | typedef T element_type; 1218 | typedef T & reference; 1219 | typedef T * pointer; 1220 | typedef T const * const_pointer; 1221 | typedef T const & const_reference; 1222 | 1223 | typedef pointer iterator; 1224 | typedef const_pointer const_iterator; 1225 | 1226 | typedef std::reverse_iterator< iterator > reverse_iterator; 1227 | typedef std::reverse_iterator< const_iterator > const_reverse_iterator; 1228 | 1229 | typedef typename std::iterator_traits< iterator >::difference_type difference_type; 1230 | 1231 | gsl_api gsl_constexpr14 span() gsl_noexcept 1232 | : first_( gsl_nullptr ) 1233 | , last_ ( gsl_nullptr ) 1234 | { 1235 | Expects( size() == 0 ); 1236 | } 1237 | 1238 | #if gsl_HAVE_NULLPTR 1239 | gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in ) 1240 | : first_( nullptr ) 1241 | , last_ ( nullptr ) 1242 | { 1243 | Expects( size_in == 0 ); 1244 | } 1245 | #endif 1246 | 1247 | #if gsl_HAVE_IS_DELETE 1248 | gsl_api gsl_constexpr14 span( reference data_in ) 1249 | : span( &data_in, 1 ) 1250 | {} 1251 | 1252 | gsl_api gsl_constexpr14 span( element_type && ) = delete; 1253 | #endif 1254 | 1255 | gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in ) 1256 | : first_( first_in ) 1257 | , last_ ( last_in ) 1258 | { 1259 | Expects( first_in <= last_in ); 1260 | } 1261 | 1262 | gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in ) 1263 | : first_( data_in ) 1264 | , last_ ( data_in + size_in ) 1265 | { 1266 | Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); 1267 | } 1268 | 1269 | template< class U > 1270 | gsl_api gsl_constexpr14 span( U * & data_in, index_type size_in ) 1271 | : first_( data_in ) 1272 | , last_ ( data_in + size_in ) 1273 | { 1274 | Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); 1275 | } 1276 | 1277 | template< class U > 1278 | gsl_api gsl_constexpr14 span( U * const & data_in, index_type size_in ) 1279 | : first_( data_in ) 1280 | , last_ ( data_in + size_in ) 1281 | { 1282 | Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); 1283 | } 1284 | 1285 | template< class U, size_t N > 1286 | gsl_api gsl_constexpr14 span( U (&arr)[N] ) gsl_noexcept 1287 | : first_( &arr[0] ) 1288 | , last_ ( &arr[0] + N ) 1289 | {} 1290 | 1291 | #if gsl_HAVE_ARRAY 1292 | template< class U, size_t N > 1293 | gsl_api gsl_constexpr14 span( std::array< U, N > & arr ) 1294 | : first_( arr.data() ) 1295 | , last_ ( arr.data() + N ) 1296 | {} 1297 | 1298 | template< class U, size_t N > 1299 | gsl_api gsl_constexpr14 span( std::array< U, N > const & arr ) 1300 | : first_( arr.data() ) 1301 | , last_ ( arr.data() + N ) 1302 | {} 1303 | #endif 1304 | 1305 | #if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR 1306 | // SFINAE enable only if Cont has a data() member function 1307 | template< class Cont, class = decltype(std::declval().data()) > 1308 | gsl_api gsl_constexpr14 span( Cont & cont ) 1309 | : first_( cont.data() ) 1310 | , last_ ( cont.data() + cont.size() ) 1311 | {} 1312 | #elif gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR 1313 | template< class Cont > 1314 | gsl_api gsl_constexpr14 span( Cont & cont ) 1315 | : first_( cont.size() == 0 ? gsl_nullptr : &cont[0] ) 1316 | , last_ ( cont.size() == 0 ? gsl_nullptr : &cont[0] + cont.size() ) 1317 | {} 1318 | #endif 1319 | 1320 | template< class Cont > 1321 | gsl_api gsl_constexpr14 span( with_container_t, Cont & cont ) 1322 | : first_( cont.size() == 0 ? gsl_nullptr : &cont[0] ) 1323 | , last_ ( cont.size() == 0 ? gsl_nullptr : &cont[0] + cont.size() ) 1324 | {} 1325 | 1326 | // constructor taking shared_ptr deprecated since 0.29.0 1327 | 1328 | #if gsl_HAVE_SHARED_PTR 1329 | gsl_api gsl_constexpr14 span( shared_ptr const & ptr ) 1330 | : first_( ptr.get() ) 1331 | , last_ ( ptr.get() ? ptr.get() + 1 : 0 ) 1332 | {} 1333 | #endif 1334 | 1335 | // constructors taking unique_ptr deprecated since 0.29.0 1336 | 1337 | #if gsl_HAVE_UNIQUE_PTR 1338 | # if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1339 | template< class ArrayElementType = typename std::add_pointer::type > 1340 | # else 1341 | template< class ArrayElementType > 1342 | # endif 1343 | gsl_api gsl_constexpr14 span( unique_ptr const & ptr, index_type count ) 1344 | : first_( ptr.get() ) 1345 | , last_ ( ptr.get() + count ) 1346 | {} 1347 | 1348 | gsl_api gsl_constexpr14 span( unique_ptr const & ptr ) 1349 | : first_( ptr.get() ) 1350 | , last_ ( ptr.get() ? ptr.get() + 1 : 0 ) 1351 | {} 1352 | #endif 1353 | 1354 | #if gsl_HAVE_IS_DEFAULT && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600) 1355 | gsl_api gsl_constexpr14 span( span && ) = default; 1356 | gsl_api gsl_constexpr14 span( span const & ) = default; 1357 | #else 1358 | gsl_api gsl_constexpr14 span( span const & other ) 1359 | : first_( other.begin() ) 1360 | , last_ ( other.end() ) 1361 | {} 1362 | #endif 1363 | 1364 | template< class U > 1365 | gsl_api gsl_constexpr14 span( span const & other ) 1366 | : first_( other.begin() ) 1367 | , last_ ( other.end() ) 1368 | {} 1369 | 1370 | #if gsl_HAVE_IS_DEFAULT 1371 | ~span() = default; 1372 | #else 1373 | ~span() {} 1374 | #endif 1375 | 1376 | #if gsl_HAVE_IS_DEFAULT 1377 | gsl_api span & operator=( span && ) = default; 1378 | gsl_api span & operator=( span const & ) = default; 1379 | #else 1380 | gsl_api span & operator=( span other ) 1381 | { 1382 | other.swap( *this ); 1383 | return *this; 1384 | } 1385 | #endif 1386 | 1387 | #if 0 1388 | // Converting from other span ? 1389 | template< class U > operator=(); 1390 | #endif 1391 | 1392 | gsl_api gsl_constexpr14 span first( index_type count ) const gsl_noexcept 1393 | { 1394 | Expects( count <= this->size() ); 1395 | return span( this->data(), count ); 1396 | } 1397 | 1398 | gsl_api gsl_constexpr14 span last( index_type count ) const gsl_noexcept 1399 | { 1400 | Expects( count <= this->size() ); 1401 | return span( this->data() + this->size() - count, count ); 1402 | } 1403 | 1404 | gsl_api gsl_constexpr14 span subspan( index_type offset ) const gsl_noexcept 1405 | { 1406 | Expects( offset <= this->size() ); 1407 | return span( this->data() + offset, this->size() - offset ); 1408 | } 1409 | 1410 | gsl_api gsl_constexpr14 span subspan( index_type offset, index_type count ) const gsl_noexcept 1411 | { 1412 | Expects( offset <= this->size() && count <= this->size() - offset ); 1413 | return span( this->data() + offset, count ); 1414 | } 1415 | 1416 | gsl_api gsl_constexpr14 iterator begin() const gsl_noexcept 1417 | { 1418 | return iterator( first_ ); 1419 | } 1420 | 1421 | gsl_api gsl_constexpr14 iterator end() const gsl_noexcept 1422 | { 1423 | return iterator( last_ ); 1424 | } 1425 | 1426 | gsl_api gsl_constexpr14 const_iterator cbegin() const gsl_noexcept 1427 | { 1428 | #if gsl_CPP11_OR_GREATER 1429 | return { begin() }; 1430 | #else 1431 | return const_iterator( begin() ); 1432 | #endif 1433 | } 1434 | 1435 | gsl_api gsl_constexpr14 const_iterator cend() const gsl_noexcept 1436 | { 1437 | #if gsl_CPP11_OR_GREATER 1438 | return { end() }; 1439 | #else 1440 | return const_iterator( end() ); 1441 | #endif 1442 | } 1443 | 1444 | gsl_api gsl_constexpr14 reverse_iterator rbegin() const gsl_noexcept 1445 | { 1446 | return reverse_iterator( end() ); 1447 | } 1448 | 1449 | gsl_api gsl_constexpr14 reverse_iterator rend() const gsl_noexcept 1450 | { 1451 | return reverse_iterator( begin() ); 1452 | } 1453 | 1454 | gsl_api gsl_constexpr14 const_reverse_iterator crbegin() const gsl_noexcept 1455 | { 1456 | return const_reverse_iterator( cend() ); 1457 | } 1458 | 1459 | gsl_api gsl_constexpr14 const_reverse_iterator crend() const gsl_noexcept 1460 | { 1461 | return const_reverse_iterator( cbegin() ); 1462 | } 1463 | 1464 | gsl_api gsl_constexpr14 reference operator[]( index_type index ) const 1465 | { 1466 | return at( index ); 1467 | } 1468 | 1469 | gsl_api gsl_constexpr14 reference operator()( index_type index ) const 1470 | { 1471 | return at( index ); 1472 | } 1473 | 1474 | gsl_api gsl_constexpr14 reference at( index_type index ) const 1475 | { 1476 | Expects( index < size() ); 1477 | return first_[ index ]; 1478 | } 1479 | 1480 | gsl_api gsl_constexpr14 pointer data() const gsl_noexcept 1481 | { 1482 | return first_; 1483 | } 1484 | 1485 | gsl_api gsl_constexpr14 bool empty() const gsl_noexcept 1486 | { 1487 | return size() == 0; 1488 | } 1489 | 1490 | gsl_api gsl_constexpr14 index_type size() const gsl_noexcept 1491 | { 1492 | return narrow_cast( last_ - first_ ); 1493 | } 1494 | 1495 | // member length() deprecated since 0.29.0 1496 | 1497 | gsl_api gsl_constexpr14 index_type length() const gsl_noexcept 1498 | { 1499 | return size(); 1500 | } 1501 | 1502 | gsl_api gsl_constexpr14 index_type size_bytes() const gsl_noexcept 1503 | { 1504 | return size() * narrow_cast( sizeof( element_type ) ); 1505 | } 1506 | 1507 | // member length_bytes() deprecated since 0.29.0 1508 | 1509 | gsl_api gsl_constexpr14 index_type length_bytes() const gsl_noexcept 1510 | { 1511 | return size_bytes(); 1512 | } 1513 | 1514 | gsl_api void swap( span & other ) gsl_noexcept 1515 | { 1516 | using std::swap; 1517 | swap( first_, other.first_ ); 1518 | swap( last_ , other.last_ ); 1519 | } 1520 | 1521 | // member as_bytes(), as_writeable_bytes deprecated since 0.17.0 1522 | 1523 | gsl_api span< const byte > as_bytes() const gsl_noexcept 1524 | { 1525 | return span< const byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT 1526 | } 1527 | 1528 | gsl_api span< byte > as_writeable_bytes() const gsl_noexcept 1529 | { 1530 | return span< byte >( reinterpret_cast( data() ), size_bytes() ); // NOLINT 1531 | } 1532 | 1533 | template< class U > 1534 | gsl_api span< U > as_span() const gsl_noexcept 1535 | { 1536 | Expects( ( this->size_bytes() % sizeof(U) ) == 0 ); 1537 | return span< U >( reinterpret_cast( this->data() ), this->size_bytes() / sizeof( U ) ); // NOLINT 1538 | } 1539 | 1540 | private: 1541 | pointer first_; 1542 | pointer last_; 1543 | }; 1544 | 1545 | // span comparison functions 1546 | 1547 | #if gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1548 | 1549 | template< class T, class U > 1550 | gsl_api inline gsl_constexpr14 bool operator==( span const & l, span const & r ) 1551 | { 1552 | return l.size() == r.size() 1553 | && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); 1554 | } 1555 | 1556 | template< class T, class U > 1557 | gsl_api inline gsl_constexpr14 bool operator< ( span const & l, span const & r ) 1558 | { 1559 | return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); 1560 | } 1561 | 1562 | #else 1563 | 1564 | template< class T > 1565 | gsl_api inline gsl_constexpr14 bool operator==( span const & l, span const & r ) 1566 | { 1567 | return l.size() == r.size() 1568 | && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); 1569 | } 1570 | 1571 | template< class T > 1572 | gsl_api inline gsl_constexpr14 bool operator< ( span const & l, span const & r ) 1573 | { 1574 | return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); 1575 | } 1576 | #endif 1577 | 1578 | template< class T, class U > 1579 | gsl_api inline gsl_constexpr14 bool operator!=( span const & l, span const & r ) 1580 | { 1581 | return !( l == r ); 1582 | } 1583 | 1584 | template< class T, class U > 1585 | gsl_api inline gsl_constexpr14 bool operator<=( span const & l, span const & r ) 1586 | { 1587 | return !( r < l ); 1588 | } 1589 | 1590 | template< class T, class U > 1591 | gsl_api inline gsl_constexpr14 bool operator> ( span const & l, span const & r ) 1592 | { 1593 | return ( r < l ); 1594 | } 1595 | 1596 | template< class T, class U > 1597 | gsl_api inline gsl_constexpr14 bool operator>=( span const & l, span const & r ) 1598 | { 1599 | return !( l < r ); 1600 | } 1601 | 1602 | // span algorithms 1603 | 1604 | namespace detail { 1605 | 1606 | template< class II, class N, class OI > 1607 | gsl_api inline OI copy_n( II first, N count, OI result ) 1608 | { 1609 | if ( count > 0 ) 1610 | { 1611 | *result++ = *first; 1612 | for ( N i = 1; i < count; ++i ) 1613 | { 1614 | *result++ = *++first; 1615 | } 1616 | } 1617 | return result; 1618 | } 1619 | } 1620 | 1621 | template< class T, class U > 1622 | gsl_api inline void copy( span src, span dest ) 1623 | { 1624 | #if gsl_CPP14_OR_GREATER // gsl_HAVE_TYPE_TRAITS (circumvent Travis clang 3.4) 1625 | static_assert( std::is_assignable::value, "Cannot assign elements of source span to elements of destination span" ); 1626 | #endif 1627 | Expects( dest.size() >= src.size() ); 1628 | detail::copy_n( src.data(), src.size(), dest.data() ); 1629 | } 1630 | 1631 | // span creator functions (see ctors) 1632 | 1633 | template< class T > 1634 | gsl_api inline span< const byte > as_bytes( span spn ) gsl_noexcept 1635 | { 1636 | return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT 1637 | } 1638 | 1639 | template< class T> 1640 | gsl_api inline span< byte > as_writeable_bytes( span spn ) gsl_noexcept 1641 | { 1642 | return span< byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT 1643 | } 1644 | 1645 | template< class T > 1646 | gsl_api inline gsl_constexpr14 span make_span( T * first, T * last ) 1647 | { 1648 | return span( first, last ); 1649 | } 1650 | 1651 | template< class T > 1652 | gsl_api inline gsl_constexpr14 span make_span( T * ptr, typename span::index_type count ) 1653 | { 1654 | return span( ptr, count ); 1655 | } 1656 | 1657 | template< class T, size_t N > 1658 | gsl_api inline gsl_constexpr14 span make_span( T (&arr)[N] ) 1659 | { 1660 | return span( &arr[0], N ); 1661 | } 1662 | 1663 | #if gsl_HAVE_ARRAY 1664 | 1665 | template< class T, size_t N > 1666 | gsl_api inline gsl_constexpr14 span make_span( std::array & arr ) 1667 | { 1668 | return span( arr ); 1669 | } 1670 | 1671 | template< class T, size_t N > 1672 | gsl_api inline gsl_constexpr14 span make_span( std::array const & arr ) 1673 | { 1674 | return span( arr ); 1675 | } 1676 | #endif 1677 | 1678 | #if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR && gsl_HAVE_AUTO 1679 | 1680 | template< class Cont > 1681 | gsl_api inline gsl_constexpr14 auto make_span( Cont & cont ) -> span< typename Cont::value_type > 1682 | { 1683 | return span< typename Cont::value_type >( cont ); 1684 | } 1685 | 1686 | template< class Cont > 1687 | gsl_api inline gsl_constexpr14 auto make_span( Cont const & cont ) -> span< const typename Cont::value_type > 1688 | { 1689 | return span< const typename Cont::value_type >( cont ); 1690 | } 1691 | 1692 | #else 1693 | 1694 | template< class T > 1695 | gsl_api inline span make_span( std::vector & cont ) 1696 | { 1697 | return span( with_container, cont ); 1698 | } 1699 | 1700 | template< class T > 1701 | gsl_api inline span make_span( std::vector const & cont ) 1702 | { 1703 | return span( with_container, cont ); 1704 | } 1705 | #endif 1706 | 1707 | template< class Ptr > 1708 | gsl_api inline span make_span( Ptr & ptr ) 1709 | { 1710 | return span( ptr ); 1711 | } 1712 | 1713 | template< class Ptr > 1714 | span make_span( Ptr & ptr, typename span::index_type count ) 1715 | { 1716 | return span( ptr, count); 1717 | } 1718 | 1719 | // 1720 | // basic_string_span: 1721 | // 1722 | 1723 | template< class T > 1724 | class basic_string_span; 1725 | 1726 | namespace detail { 1727 | 1728 | template< class T > 1729 | struct is_basic_string_span_oracle : false_type {}; 1730 | 1731 | template< class T > 1732 | struct is_basic_string_span_oracle< basic_string_span > : true_type {}; 1733 | 1734 | template< class T > 1735 | struct is_basic_string_span : is_basic_string_span_oracle< typename remove_cv::type > {}; 1736 | 1737 | template< class T > 1738 | gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) 1739 | { 1740 | if ( ptr == gsl_nullptr || max <= 0 ) 1741 | return 0; 1742 | 1743 | std::size_t len = 0; 1744 | while ( len < max && ptr[len] ) // NOLINT 1745 | ++len; 1746 | 1747 | return len; 1748 | } 1749 | 1750 | } // namespace detail 1751 | 1752 | // 1753 | // basic_string_span<> - A view of contiguous characters, replace (*,len). 1754 | // 1755 | template< class T > 1756 | class basic_string_span 1757 | { 1758 | public: 1759 | typedef T element_type; 1760 | typedef span span_type; 1761 | 1762 | typedef typename span_type::index_type index_type; 1763 | typedef typename span_type::difference_type difference_type; 1764 | 1765 | typedef typename span_type::pointer pointer ; 1766 | typedef typename span_type::reference reference ; 1767 | 1768 | typedef typename span_type::iterator iterator ; 1769 | typedef typename span_type::const_iterator const_iterator ; 1770 | typedef typename span_type::reverse_iterator reverse_iterator; 1771 | typedef typename span_type::const_reverse_iterator const_reverse_iterator; 1772 | 1773 | // construction: 1774 | 1775 | #if gsl_HAVE_IS_DEFAULT 1776 | gsl_api gsl_constexpr basic_string_span() gsl_noexcept = default; 1777 | #else 1778 | gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} 1779 | #endif 1780 | 1781 | #if gsl_HAVE_NULLPTR 1782 | gsl_api gsl_constexpr basic_string_span( std::nullptr_t ptr ) gsl_noexcept 1783 | : span_( ptr, 0 ) 1784 | {} 1785 | #endif 1786 | 1787 | gsl_api gsl_constexpr basic_string_span( pointer ptr ) 1788 | : span_( remove_z( ptr, std::numeric_limits::max() ) ) 1789 | {} 1790 | 1791 | gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) 1792 | : span_( ptr, count ) 1793 | {} 1794 | 1795 | gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem ) 1796 | : span_( firstElem, lastElem ) 1797 | {} 1798 | 1799 | template< std::size_t N > 1800 | gsl_api gsl_constexpr basic_string_span( element_type (&arr)[N] ) 1801 | : span_( remove_z( &arr[0], N ) ) 1802 | {} 1803 | 1804 | #if gsl_HAVE_ARRAY 1805 | 1806 | template< std::size_t N > 1807 | gsl_api gsl_constexpr basic_string_span( std::array< typename detail::remove_const::type, N> & arr ) 1808 | : span_( remove_z( arr ) ) 1809 | {} 1810 | 1811 | template< std::size_t N > 1812 | gsl_api gsl_constexpr basic_string_span( std::array< typename detail::remove_const::type, N> const & arr ) 1813 | : span_( remove_z( arr ) ) 1814 | {} 1815 | 1816 | #endif 1817 | 1818 | #if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR 1819 | 1820 | // Exclude: array, [basic_string,] basic_string_span 1821 | 1822 | template< 1823 | class Cont, 1824 | class = typename std::enable_if< 1825 | ! detail::is_std_array< Cont >::value 1826 | && ! detail::is_basic_string_span< Cont >::value 1827 | && std::is_convertible< typename Cont::pointer, pointer >::value 1828 | && std::is_convertible< typename Cont::pointer, decltype(std::declval().data()) >::value 1829 | >::type 1830 | > 1831 | gsl_api gsl_constexpr basic_string_span( Cont & cont ) 1832 | : span_( ( cont ) ) 1833 | {} 1834 | 1835 | // Exclude: array, [basic_string,] basic_string_span 1836 | 1837 | template< 1838 | class Cont, 1839 | class = typename std::enable_if< 1840 | ! detail::is_std_array< Cont >::value 1841 | && ! detail::is_basic_string_span< Cont >::value 1842 | && std::is_convertible< typename Cont::pointer, pointer >::value 1843 | && std::is_convertible< typename Cont::pointer, decltype(std::declval().data()) >::value 1844 | >::type 1845 | > 1846 | gsl_api gsl_constexpr basic_string_span( Cont const & cont ) 1847 | : span_( ( cont ) ) 1848 | {} 1849 | 1850 | #elif gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR 1851 | 1852 | template< class Cont > 1853 | gsl_api gsl_constexpr basic_string_span( Cont & cont ) 1854 | : span_( cont ) 1855 | {} 1856 | 1857 | template< class Cont > 1858 | gsl_api gsl_constexpr basic_string_span( Cont const & cont ) 1859 | : span_( cont ) 1860 | {} 1861 | 1862 | #else 1863 | 1864 | template< class U > 1865 | gsl_api gsl_constexpr basic_string_span( span const & rhs ) 1866 | : span_( rhs ) 1867 | {} 1868 | 1869 | #endif 1870 | 1871 | template< class Cont > 1872 | gsl_api gsl_constexpr14 basic_string_span( with_container_t, Cont & cont ) 1873 | : span_( with_container, cont ) 1874 | {} 1875 | 1876 | #if gsl_HAVE_IS_DEFAULT 1877 | # if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 ) 1878 | gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) = default; 1879 | 1880 | gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) = default; 1881 | # else 1882 | gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) gsl_noexcept = default; 1883 | 1884 | gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) gsl_noexcept = default; 1885 | # endif 1886 | #endif 1887 | 1888 | template< class U 1889 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1890 | , class = typename std::enable_if< std::is_convertible::pointer, pointer>::value >::type 1891 | #endif 1892 | > 1893 | gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) 1894 | : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT 1895 | {} 1896 | 1897 | #if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12 1898 | template< class U 1899 | , class = typename std::enable_if< std::is_convertible::pointer, pointer>::value >::type 1900 | > 1901 | gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) 1902 | : span_( reinterpret_cast( rhs.data() ), rhs.length() ) // NOLINT 1903 | {} 1904 | #endif 1905 | 1906 | template< class CharTraits, class Allocator > 1907 | gsl_api gsl_constexpr basic_string_span( 1908 | std::basic_string< typename detail::remove_const::type, CharTraits, Allocator > & str ) 1909 | : span_( &str[0], str.length() ) 1910 | {} 1911 | 1912 | template< class CharTraits, class Allocator > 1913 | gsl_api gsl_constexpr basic_string_span( 1914 | std::basic_string< typename detail::remove_const::type, CharTraits, Allocator > const & str ) 1915 | : span_( &str[0], str.length() ) 1916 | {} 1917 | 1918 | // destruction, assignment: 1919 | 1920 | #if gsl_HAVE_IS_DEFAULT 1921 | gsl_api ~basic_string_span() gsl_noexcept = default; 1922 | 1923 | gsl_api basic_string_span & operator=( basic_string_span const & rhs ) gsl_noexcept = default; 1924 | 1925 | gsl_api basic_string_span & operator=( basic_string_span && rhs ) gsl_noexcept = default; 1926 | #endif 1927 | 1928 | // sub span: 1929 | 1930 | gsl_api gsl_constexpr basic_string_span first( index_type count ) const 1931 | { 1932 | return span_.first( count ); 1933 | } 1934 | 1935 | gsl_api gsl_constexpr basic_string_span last( index_type count ) const 1936 | { 1937 | return span_.last( count ); 1938 | } 1939 | 1940 | gsl_api gsl_constexpr basic_string_span subspan( index_type offset ) const 1941 | { 1942 | return span_.subspan( offset ); 1943 | } 1944 | 1945 | gsl_api gsl_constexpr basic_string_span subspan( index_type offset, index_type count ) const 1946 | { 1947 | return span_.subspan( offset, count ); 1948 | } 1949 | 1950 | // observers: 1951 | 1952 | gsl_api gsl_constexpr index_type length() const gsl_noexcept 1953 | { 1954 | return span_.size(); 1955 | } 1956 | 1957 | gsl_api gsl_constexpr index_type size() const gsl_noexcept 1958 | { 1959 | return span_.size(); 1960 | } 1961 | 1962 | gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept 1963 | { 1964 | return span_.size_bytes(); 1965 | } 1966 | 1967 | gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept 1968 | { 1969 | return span_.size_bytes(); 1970 | } 1971 | 1972 | gsl_api gsl_constexpr bool empty() const gsl_noexcept 1973 | { 1974 | return size() == 0; 1975 | } 1976 | 1977 | gsl_api gsl_constexpr reference operator[]( index_type idx ) const 1978 | { 1979 | return span_[idx]; 1980 | } 1981 | 1982 | gsl_api gsl_constexpr reference operator()( index_type idx ) const 1983 | { 1984 | return span_[idx]; 1985 | } 1986 | 1987 | gsl_api gsl_constexpr pointer data() const gsl_noexcept 1988 | { 1989 | return span_.data(); 1990 | } 1991 | 1992 | gsl_api iterator begin() const gsl_noexcept 1993 | { 1994 | return span_.begin(); 1995 | } 1996 | 1997 | gsl_api iterator end() const gsl_noexcept 1998 | { 1999 | return span_.end(); 2000 | } 2001 | 2002 | gsl_api reverse_iterator rbegin() const gsl_noexcept 2003 | { 2004 | return span_.rbegin(); 2005 | } 2006 | 2007 | gsl_api reverse_iterator rend() const gsl_noexcept 2008 | { 2009 | return span_.rend(); 2010 | } 2011 | 2012 | // const version not in p0123r2: 2013 | 2014 | gsl_api const_iterator cbegin() const gsl_noexcept 2015 | { 2016 | return span_.cbegin(); 2017 | } 2018 | 2019 | gsl_api const_iterator cend() const gsl_noexcept 2020 | { 2021 | return span_.cend(); 2022 | } 2023 | 2024 | gsl_api const_reverse_iterator crbegin() const gsl_noexcept 2025 | { 2026 | return span_.crbegin(); 2027 | } 2028 | 2029 | gsl_api const_reverse_iterator crend() const gsl_noexcept 2030 | { 2031 | return span_.crend(); 2032 | } 2033 | 2034 | private: 2035 | gsl_api static gsl_constexpr14 span_type remove_z( pointer const & sz, std::size_t max ) 2036 | { 2037 | return span_type( sz, detail::string_length( sz, max ) ); 2038 | } 2039 | 2040 | #if gsl_HAVE_ARRAY 2041 | template< size_t N > 2042 | gsl_api static gsl_constexpr14 span_type remove_z( std::array::type, N> & arr ) 2043 | { 2044 | return remove_z( &arr[0], narrow_cast< std::size_t >( N ) ); 2045 | } 2046 | 2047 | template< size_t N > 2048 | gsl_api static gsl_constexpr14 span_type remove_z( std::array::type, N> const & arr ) 2049 | { 2050 | return remove_z( &arr[0], narrow_cast< std::size_t >( N ) ); 2051 | } 2052 | #endif 2053 | 2054 | private: 2055 | span_type span_; 2056 | }; 2057 | 2058 | // basic_string_span comparison functions: 2059 | 2060 | #if gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 2061 | 2062 | template< class T, class U > 2063 | gsl_api inline gsl_constexpr14 bool operator==( basic_string_span const & l, U const & u ) gsl_noexcept 2064 | { 2065 | const basic_string_span< typename detail::add_const::type > r( u ); 2066 | 2067 | return l.size() == r.size() 2068 | && std::equal( l.begin(), l.end(), r.begin() ); 2069 | } 2070 | 2071 | template< class T, class U > 2072 | gsl_api inline gsl_constexpr14 bool operator<( basic_string_span const & l, U const & u ) gsl_noexcept 2073 | { 2074 | const basic_string_span< typename detail::add_const::type > r( u ); 2075 | 2076 | return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); 2077 | } 2078 | 2079 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 2080 | 2081 | template< class T, class U, 2082 | class = typename std::enable_if::value >::type > 2083 | gsl_api inline gsl_constexpr14 bool operator==( U const & u, basic_string_span const & r ) gsl_noexcept 2084 | { 2085 | const basic_string_span< typename detail::add_const::type > l( u ); 2086 | 2087 | return l.size() == r.size() 2088 | && std::equal( l.begin(), l.end(), r.begin() ); 2089 | } 2090 | 2091 | template< class T, class U, 2092 | class = typename std::enable_if::value >::type > 2093 | gsl_api inline gsl_constexpr14 bool operator<( U const & u, basic_string_span const & r ) gsl_noexcept 2094 | { 2095 | const basic_string_span< typename detail::add_const::type > l( u ); 2096 | 2097 | return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); 2098 | } 2099 | #endif 2100 | 2101 | #else //gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 2102 | 2103 | template< class T > 2104 | gsl_api inline gsl_constexpr14 bool operator==( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept 2105 | { 2106 | return l.size() == r.size() 2107 | && std::equal( l.begin(), l.end(), r.begin() ); 2108 | } 2109 | 2110 | template< class T > 2111 | gsl_api inline gsl_constexpr14 bool operator<( basic_string_span const & l, basic_string_span const & r ) gsl_noexcept 2112 | { 2113 | return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); 2114 | } 2115 | 2116 | #endif // gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 2117 | 2118 | template< class T, class U > 2119 | gsl_api inline gsl_constexpr14 bool operator!=( basic_string_span const & l, U const & r ) gsl_noexcept 2120 | { 2121 | return !( l == r ); 2122 | } 2123 | 2124 | template< class T, class U > 2125 | gsl_api inline gsl_constexpr14 bool operator<=( basic_string_span const & l, U const & r ) gsl_noexcept 2126 | { 2127 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG || ! gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 2128 | return !( r < l ); 2129 | #else 2130 | basic_string_span< typename detail::add_const::type > rr( r ); 2131 | return !( rr < l ); 2132 | #endif 2133 | } 2134 | 2135 | template< class T, class U > 2136 | gsl_api inline gsl_constexpr14 bool operator>( basic_string_span const & l, U const & r ) gsl_noexcept 2137 | { 2138 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG || ! gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 2139 | return ( r < l ); 2140 | #else 2141 | basic_string_span< typename detail::add_const::type > rr( r ); 2142 | return ( rr < l ); 2143 | #endif 2144 | } 2145 | 2146 | template< class T, class U > 2147 | gsl_api inline gsl_constexpr14 bool operator>=( basic_string_span const & l, U const & r ) gsl_noexcept 2148 | { 2149 | return !( l < r ); 2150 | } 2151 | 2152 | #if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 2153 | 2154 | template< class T, class U, 2155 | class = typename std::enable_if::value >::type > 2156 | gsl_api inline gsl_constexpr14 bool operator!=( U const & l, basic_string_span const & r ) gsl_noexcept 2157 | { 2158 | return !( l == r ); 2159 | } 2160 | 2161 | template< class T, class U, 2162 | class = typename std::enable_if::value >::type > 2163 | gsl_api inline gsl_constexpr14 bool operator<=( U const & l, basic_string_span const & r ) gsl_noexcept 2164 | { 2165 | return !( r < l ); 2166 | } 2167 | 2168 | template< class T, class U, 2169 | class = typename std::enable_if::value >::type > 2170 | gsl_api inline gsl_constexpr14 bool operator>( U const & l, basic_string_span const & r ) gsl_noexcept 2171 | { 2172 | return ( r < l ); 2173 | } 2174 | 2175 | template< class T, class U, 2176 | class = typename std::enable_if::value >::type > 2177 | gsl_api inline gsl_constexpr14 bool operator>=( U const & l, basic_string_span const & r ) gsl_noexcept 2178 | { 2179 | return !( l < r ); 2180 | } 2181 | 2182 | #endif // gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 2183 | 2184 | // convert basic_string_span to byte span: 2185 | 2186 | template< class T > 2187 | gsl_api inline span< const byte > as_bytes( basic_string_span spn ) gsl_noexcept 2188 | { 2189 | return span< const byte >( reinterpret_cast( spn.data() ), spn.size_bytes() ); // NOLINT 2190 | } 2191 | 2192 | // 2193 | // String types: 2194 | // 2195 | 2196 | typedef char * zstring; 2197 | typedef const char * czstring; 2198 | 2199 | #if gsl_HAVE_WCHAR 2200 | typedef wchar_t * zwstring; 2201 | typedef const wchar_t * cwzstring; 2202 | #endif 2203 | 2204 | typedef basic_string_span< char > string_span; 2205 | typedef basic_string_span< char const > cstring_span; 2206 | 2207 | #if gsl_HAVE_WCHAR 2208 | typedef basic_string_span< wchar_t > wstring_span; 2209 | typedef basic_string_span< wchar_t const > cwstring_span; 2210 | #endif 2211 | 2212 | // to_string() allow (explicit) conversions from string_span to string 2213 | 2214 | #if 0 2215 | 2216 | template< class T > 2217 | gsl_api inline std::basic_string< typename std::remove_const::type > to_string( basic_string_span spn ) 2218 | { 2219 | std::string( spn.data(), spn.length() ); 2220 | } 2221 | 2222 | #else 2223 | 2224 | gsl_api inline std::string to_string( string_span const & spn ) 2225 | { 2226 | return std::string( spn.data(), spn.length() ); 2227 | } 2228 | 2229 | gsl_api inline std::string to_string( cstring_span const & spn ) 2230 | { 2231 | return std::string( spn.data(), spn.length() ); 2232 | } 2233 | 2234 | #if gsl_HAVE_WCHAR 2235 | 2236 | gsl_api inline std::wstring to_string( wstring_span const & spn ) 2237 | { 2238 | return std::wstring( spn.data(), spn.length() ); 2239 | } 2240 | 2241 | gsl_api inline std::wstring to_string( cwstring_span const & spn ) 2242 | { 2243 | return std::wstring( spn.data(), spn.length() ); 2244 | } 2245 | 2246 | #endif // gsl_HAVE_WCHAR 2247 | #endif // to_string() 2248 | 2249 | // 2250 | // Stream output for string_span types 2251 | // 2252 | 2253 | namespace detail { 2254 | 2255 | template< class Stream > 2256 | gsl_api void write_padding( Stream & os, std::streamsize n ) 2257 | { 2258 | for ( std::streamsize i = 0; i < n; ++i ) 2259 | os.rdbuf()->sputc( os.fill() ); 2260 | } 2261 | 2262 | template< class Stream, class Span > 2263 | gsl_api Stream & write_to_stream( Stream & os, Span const & spn ) 2264 | { 2265 | typename Stream::sentry sentry( os ); 2266 | 2267 | if ( !os ) 2268 | return os; 2269 | 2270 | const std::streamsize length = narrow( spn.length() ); 2271 | 2272 | // Whether, and how, to pad 2273 | const bool pad = ( length < os.width() ); 2274 | const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; 2275 | 2276 | if ( left_pad ) 2277 | write_padding( os, os.width() - length ); 2278 | 2279 | // Write span characters 2280 | os.rdbuf()->sputn( spn.begin(), length ); 2281 | 2282 | if ( pad && !left_pad ) 2283 | write_padding( os, os.width() - length ); 2284 | 2285 | // Reset output stream width 2286 | os.width(0); 2287 | 2288 | return os; 2289 | } 2290 | 2291 | } // namespace detail 2292 | 2293 | template< typename Traits > 2294 | gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) 2295 | { 2296 | return detail::write_to_stream( os, spn ); 2297 | } 2298 | 2299 | template< typename Traits > 2300 | gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) 2301 | { 2302 | return detail::write_to_stream( os, spn ); 2303 | } 2304 | 2305 | #if gsl_HAVE_WCHAR 2306 | 2307 | template< typename Traits > 2308 | gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) 2309 | { 2310 | return detail::write_to_stream( os, spn ); 2311 | } 2312 | 2313 | template< typename Traits > 2314 | gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) 2315 | { 2316 | return detail::write_to_stream( os, spn ); 2317 | } 2318 | 2319 | #endif // gsl_HAVE_WCHAR 2320 | 2321 | // 2322 | // ensure_sentinel() 2323 | // 2324 | // Provides a way to obtain a span from a contiguous sequence 2325 | // that ends with a (non-inclusive) sentinel value. 2326 | // 2327 | // Will fail-fast if sentinel cannot be found before max elements are examined. 2328 | // 2329 | namespace detail { 2330 | 2331 | template< class T, class SizeType, const T Sentinel > 2332 | gsl_api static span ensure_sentinel( T * seq, SizeType max = std::numeric_limits::max() ) 2333 | { 2334 | typedef T * pointer; 2335 | 2336 | gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" ) 2337 | 2338 | pointer cur = seq; 2339 | 2340 | while ( static_cast( cur - seq ) < max && *cur != Sentinel ) 2341 | ++cur; 2342 | 2343 | Expects( *cur == Sentinel ); 2344 | 2345 | return span( seq, narrow_cast< typename span::index_type >( cur - seq ) ); 2346 | } 2347 | } // namespace detail 2348 | 2349 | // 2350 | // ensure_z - creates a string_span for a czstring or cwzstring. 2351 | // Will fail fast if a null-terminator cannot be found before 2352 | // the limit of size_type. 2353 | // 2354 | 2355 | template< class T > 2356 | gsl_api inline span ensure_z( T * const & sz, size_t max = std::numeric_limits::max() ) 2357 | { 2358 | return detail::ensure_sentinel( sz, max ); 2359 | } 2360 | 2361 | template< class T, size_t N > 2362 | gsl_api inline span ensure_z( T (&sz)[N] ) 2363 | { 2364 | return ensure_z( &sz[0], N ); 2365 | } 2366 | 2367 | # if gsl_HAVE_TYPE_TRAITS 2368 | 2369 | template< class Cont > 2370 | gsl_api inline span< typename std::remove_pointer::type > 2371 | ensure_z( Cont & cont ) 2372 | { 2373 | return ensure_z( cont.data(), cont.length() ); 2374 | } 2375 | # endif 2376 | 2377 | } // namespace gsl 2378 | 2379 | #if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12 2380 | 2381 | namespace std { 2382 | 2383 | template<> 2384 | struct hash< gsl::byte > 2385 | { 2386 | public: 2387 | std::size_t operator()( gsl::byte v ) const gsl_noexcept 2388 | { 2389 | return gsl::to_integer( v ); 2390 | } 2391 | }; 2392 | 2393 | } // namespace std 2394 | 2395 | #endif 2396 | 2397 | gsl_RESTORE_MSVC_WARNINGS() 2398 | 2399 | #endif // GSL_GSL_LITE_HPP_INCLUDED 2400 | 2401 | // end of file 2402 | --------------------------------------------------------------------------------