1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT license. 3 4 #pragma once 5 6 #include "seal/util/common.h" 7 #include "seal/util/defines.h" 8 #include "seal/util/pointer.h" 9 #include <algorithm> 10 #include <cstddef> 11 #include <cstdint> 12 #include <iostream> 13 #include <iterator> 14 #include <stdexcept> 15 #include <tuple> 16 #include <type_traits> 17 #include <utility> 18 #include <vector> 19 20 namespace seal 21 { 22 class Ciphertext; 23 24 namespace util 25 { 26 class NTTTables; 27 28 /** 29 @par PolyIter, RNSIter, and CoeffIter 30 In this file we define a set of custom iterator classes ("SEAL iterators") that are used throughout Microsoft 31 SEAL for easier iteration over ciphertext polynomials, their RNS components, and the coefficients in the RNS 32 components. All SEAL iterators satisfy the C++ LegacyRandomAccessIterator requirements. SEAL iterators are ideal 33 to use with the SEAL_ITERATE macro, which expands to std::for_each_n in C++17 and to seal::util::seal_for_each_n 34 in C++14. All SEAL iterators derive from SEALIterBase. 35 36 The most important SEAL iterator classes behave as illustrated by the following diagram: 37 38 +-------------------+ 39 | Pointer & Size | Construct +-----------------+ 40 | or Ciphertext |------------>| (Const)PolyIter | Iterates over RNS polynomials in a ciphertext 41 +-------------------+ +--------+--------+ (coeff_modulus_size-many RNS components) 42 | 43 | 44 | Dereference 45 | 46 | 47 v 48 +----------------+ Construct +----------------+ 49 | Pointer & Size |------------->| (Const)RNSIter | Iterates over RNS components in an RNS polynomial 50 +----------------+ +-------+--------+ (poly_modulus_degree-many coefficients) 51 | 52 | 53 | Dereference 54 | 55 | 56 v 57 +----------------+ Construct +------------------+ 58 | Pointer & Size |------------>| (Const)CoeffIter | Iterates over coefficients (std::uint64_t) in a single 59 +----------------+ +---------+--------+ RNS polynomial component 60 | 61 | 62 | Dereference 63 | 64 | 65 v 66 +-------------------------+ 67 | (const) std::uint64_t & | 68 +-------------------------+ 69 70 @par PtrIter and StrideIter 71 PtrIter<T *> and StrideIter<T *> are both templated SEAL iterators that wrap raw pointers. The difference 72 between these two types is that advancing PtrIter<T *> always advances the wrapped pointer by one, whereas the 73 step size (stride) can be set to be anything for a StrideIter<T *>. CoeffIter is a typedef of 74 PtrIter<std::uint64_t *> and and RNSIter is almost the same as StrideIter<std::uint64_t *>, but still a 75 different type. 76 77 +----------+ Construct +-------------------+ 78 | MyType * |------------->| PtrIter<MyType *> | Simple wrapper for raw pointers 79 +----------+ +----+----------+---+ 80 | | 81 | | 82 Dereference | | PtrIter<MyType *>::ptr() 83 | | or implicit conversion 84 | | 85 v v 86 +----------+ +----------+ 87 | MyType & | | MyType * | 88 +----------+ +----------+ 89 90 +----------+ Construct +----------------------+ 91 | MyType * |------------->| StrideIter<MyType *> | Simple wrapper for raw pointers with custom stride size 92 +----------+ +-----+----------+-----+ 93 | | 94 | | 95 Dereference | | StrideIter<MyType *>::ptr() 96 | | or implicit conversion 97 | | 98 v v 99 +----------+ +----------+ 100 | MyType & | | MyType * | 101 +----------+ +----------+ 102 103 @par IterTuple 104 An extremely useful template class is the (variadic) IterTuple<...> that allows multiple SEAL iterators to be 105 zipped together. An IterTuple is itself a SEAL iterator and nested IterTuple types are used commonly in the 106 library. Dereferencing an IterTuple always yields an std::tuple, with each IterTuple element dereferenced. 107 Since an IterTuple can be constructed from an std::tuple holding the respective single-parameter constructor 108 arguments for each iterator, the dereferenced std::tuple can often be directly passed on to functions expecting 109 an IterTuple. 110 111 The individual components of an IterTuple can be accessed with the seal::util::get<i>(...) functions. The 112 behavior of IterTuple is summarized in the following diagram: 113 114 +-----------------------------------------+ 115 | IterTuple<PolyIter, RNSIter, CoeffIter> | 116 +--------------------+--------------------+ 117 | 118 | 119 | Dereference 120 | 121 | 122 v 123 +--------------------------------------------------+ 124 | std::tuple<RNSIter, CoeffIter, std::uint64_t &>> | 125 +------+-------------------+-------------------+---+ 126 | | | 127 | | | 128 | std::get<0> | std::get<1> | std::get<2> 129 | | | 130 | | | 131 v v v 132 +-------------+ +---------------+ +-----------------+ 133 | RNSIter | | CoeffIter | | std::uint64_t & | 134 +-------------+ +---------------+ +-----------------+ 135 136 Sometimes we have to use multiple nested iterator tuples. In this case accessing the nested iterators can be 137 tedious with nested get<...> calls. Consider the following, where encrypted1 and encrypted2 are Ciphertexts 138 and destination is either a Ciphertext or a PolyIter: 139 140 IterTuple<PolyIter, PolyIter> I(encrypted1, encrypted2); 141 IterTuple<decltype(I), PolyIter> J(I, destination); 142 auto encrypted1_iter = get<0>(get<0>(J)); 143 auto encrypted2_iter = get<1>(get<0>(J)); 144 145 An easier way is to use another form of get<...> that accepts multiple indices and accesses the structure in a 146 nested manner. For example, in the above we could also write: 147 148 auto encrypted1_iter = get<0, 0>(J)); 149 auto encrypted2_iter = get<0, 1>(J)); 150 151 Note that the innermost tuple index appears first in the list, i.e. the order is reversed from what appears in 152 a nested get<...> call. The reason for this reversal is that, when deducing what the iterators are, one first 153 examines at the innermost scope, and last the outermost scope, corresponding now to the order of the indices. 154 We have also provided similar functions for nested std::tuple objects, which is necessary when accessing 155 the dereferencing of a nested IterTuple. 156 157 @par Typedefs for common PtrIter types 158 It is very common to use the types PtrIter<Modulus *> and PtrIter<NTTTables *>. To simplify the 159 notation, we have set up typedefs for these: ModulusIter and NTTTablesIter. There are also constant versions 160 ConstModulusIter and ConstNTTTablesIter, wrapping pointers to constant Modulus and NTTTables instead. 161 162 @par Creating SEAL iterators 163 Iterators are easiest to create using the variadic iter function that, when given one or more arguments that can 164 naturally be converted to SEAL iterators, outputs an appropriate iterator, or iterator tuple. Consider again the 165 code snippet above, and how confusing the template parameters can become to write. Instead, we can simply write: 166 167 auto I = iter(encrypted1, encrypted2); 168 auto J = iter(I, destination); 169 auto encrypted1_iter = get<0, 0>(J)); 170 auto encrypted2_iter = get<0, 1>(J)); 171 172 There are three ways to create IterTuples from the iter function. The first way is by passing an IterTuple as 173 input, in which case iter outputs a copy of it; there should be no reason to do this. The second way is by 174 passing a variadic set of constructor arguments; iter will output an IterTuple consisting of SEAL iterators 175 that are compatible with the given constructor arguments. The third way is by passing a std::tuple consisting 176 of a variadic set of constructor arguments; the behavior is as in the second way. 177 178 @par Reversing direction with ReverseIter 179 In addition to the iterator types described above, we provide ReverseIter<SEALIter> that reverses the direction 180 of iteration. ReverseIter<SEALIter> dereferences to the same type as SEALIter: for example, dereferencing 181 ReverseIter<RNSIter> results in CoeffIter, not ReverseIter<CoeffIter>. 182 183 It is easy to create a ReverseIter from a given SEAL iterator using the function reverse_iter. For example, 184 reverse_iter(encrypted) will return a ReverseIter<PolyIter> if encrypted is either a PolyIter, or a Ciphertext. 185 When passed multiple arguments, reverse_iter returns an appropriate ReverseIter<IterTuple<...>>. For example, 186 reverse_iter(encrypted1, encrypted2) returns ReverseIter<IterTuple<PolyIter, PolyIter>> if encrypted1 and 187 encrypted2 are PolyIter or Ciphertext objects. 188 189 @par SEAL_ITERATE 190 SEAL iterators are made to be used with the SEAL_ITERATE macro to iterate over a certain number of steps, and 191 for each step call a given lambda function. In C++17 SEAL_ITERATE expands to std::for_each_n, and in C++14 it 192 expands to seal::util::seal_for_each_n -- a custom implementation. For example, the following snippet appears 193 in Evaluator::bfv_multiply: 194 195 SEAL_ITERATE( 196 iter(encrypted1, encrypted1_q, encrypted1_Bsk), 197 encrypted1_size, 198 behz_extend_base_convert_to_ntt); 199 200 Here an IterTuple<PolyIter, PolyIter, PolyIter> is created with the iter function; the argument types are 201 Ciphertext (encrypted1), PolyIter (encrypted1_q), and PolyIter (encrypted1_Bsk). The iterator is advanced 202 encrypted1_size times, and each time the lambda function behz_extend_base_convert_to_ntt is called with the 203 iterator tuple dereferenced. The lambda function starts as follows: 204 205 auto behz_extend_base_convert_to_ntt = [&](auto I) { 206 set_poly(get<0>(I), coeff_count, base_q_size, get<1>(I)); 207 ntt_negacyclic_harvey_lazy(get<1>(I), base_q_size, base_q_ntt_tables); 208 ... 209 }); 210 211 Here the parameter I is of type IterTuple<RNSIter, RNSIter, RNSIter>. Inside the lambda function we first copy 212 the RNS polynomial from get<0>(I) (encrypted1) to get<1>(I) (encrypted1_q) and transform it to NTT form. We use 213 an overload of ntt_negacyclic_harvey_lazy that takes an RNSIter, size of the RNS base, and ConstNTTTablesIter as 214 arguments and converts each RNS component separately. Looking at seal/util/ntt.h we see that the function 215 ntt_negacyclic_harvey_lazy is again implemented using SEAL_ITERATE. Specifically, it contains the following: 216 217 SEAL_ITERATE(iter(operand, tables), coeff_modulus_size, [&](auto I) { 218 ntt_negacyclic_harvey_lazy(get<0>(I), get<1>(I)); 219 }); 220 221 Here iter outputs an IterTuple<RNSIter, ConstNTTTablesIter>. In this case the lambda function to be called 222 is defined inline. The argument I takes values IterTuple<CoeffIter, const NTTTables *>, and for each step the 223 CoeffIter overload of ntt_negacyclic_harvey_lazy is called, with a reference to a matching NTTTables object. 224 225 @par Coding conventions 226 There are two important coding conventions in the above code snippets that are to be observed: 227 228 1. Use I, J, K, ... for the lambda function parameters representing SEAL iterators. This is compact and 229 makes it very clear that the objects in question are SEAL iterators since such variable names should not 230 be used in SEAL in any other context. 231 2. Lambda functions passed to SEAL_ITERATE should almost always (see 3.) take a parameter of type auto. This 232 will produce simple looking code that performs well with the expected outcome. 233 3. The only exception to 2. is when SEAL_ITERATE operates on a single PtrIter<T *>: dereferencing returns a 234 T &, which may be important to forward by reference to the lambda function. For an example of this, see 235 seal::util::ntt_negacyclic_harvey in seal/util/ntt.h, where the lambda function parameter is auto &. 236 237 Note: IterTuple<PolyIter, CoeffIter> will dereference to std::tuple<RNSIter, std::uint64_t &>, which can 238 safely be passed by value to the lambda function. Hence, a parameter of type auto in the lambda function 239 will most likely work as expected. 240 241 Note: Another approach that would always behave correctly is by using a forwarding reference auto && as 242 the lambda function parameter. However, we feel that this unnecessarily complicates the code for a minor 243 benefit. 244 245 @par Iterator overloads of common functions 246 Some functions have overloads that directly take either CoeffIter, RNSIter, or PolyIter inputs, and apply the 247 operation in question to the entire structure as indicated by the iterator. For example, the function 248 seal::util::negate_poly_coeffmod can negate a single RNS component modulo a given Modulus (CoeffIter overload), 249 an entire RNS polynomial modulo an array of matching Modulus elements (RNSIter overload), or an array of RNS 250 polynomials (PolyIter overload). 251 252 @par Indexing with SeqIter 253 Sometimes inside SEAL_ITERATE lambda functions it is convenient to know the index of the iteration. This can be 254 done using a SeqIter<T> iterator. The template parameter is an arithmetic type for the index counter. 255 256 The easiest way to create SeqIter objects is using the seq_iter function. For example, seq_iter(0) returns a 257 SeqIter<int> object with initial value 0. Alternatively, the iter function will detect arithmetic types passed 258 to it and create SeqIter objects from them. For example, calling iter(0) is equivalent to calling seq_iter(0), 259 and this works also for multi-argument calls to iter. Dereferencing a SeqIter object returns the current value. 260 For opposite direction indexing, simply wrap a SeqIter into a ReverseIter, or call reverse_iter directly with 261 the start index. 262 263 @par Note on allocations 264 In the future we hope to use the parallel version of std::for_each_n, introduced in C++17. For this to work, be 265 mindful of how you use heap allocations in the lambda functions. Specifically, in heavy lambda functions it is 266 probably a good idea to call seal::util::allocate inside the lambda function for any allocations needed, rather 267 than using allocations captured from outside the lambda function. 268 269 @par Iterators to temporary allocations 270 In many cases one may want to allocate a temporary buffer and create an iterator pointing to it. However, care 271 must be taken to use the correct size parameters now both for the allocation, as well as for setting up the 272 iterator. For this reason, we provide a few helpful macros that set up the Pointer and only expose the iterator 273 to the function. For example, instead of writing the following error-prone code: 274 275 auto temp_alloc(allocate_poly_array(count, poly_modulus_degree, coeff_modulus_size, pool)); 276 PolyIter temp(temp_alloc.get(), poly_modulus_degree, coeff_modulus_size); 277 278 we can simply write: 279 280 SEAL_ALLOCATE_GET_POLY_ITER(temp, count, poly_modulus_degree, coeff_modulus_size, pool); 281 282 However, the latter does not expose the name of the allocation itself. There are similar macros for allocating 283 buffers and setting up PtrIter<T *>, StrideIter<T *>, RNSIter, and CoeffIter objects as well. 284 */ 285 286 class SEALIterBase 287 {}; 288 289 template <typename T, typename> 290 class SeqIter; 291 292 template <typename T> 293 class PtrIter; 294 295 template <typename T> 296 class StrideIter; 297 298 class RNSIter; 299 300 class ConstRNSIter; 301 302 class PolyIter; 303 304 class ConstPolyIter; 305 306 template <typename SEALIter> 307 class ReverseIter; 308 309 template <typename... SEALIters> 310 class IterTuple; 311 312 using CoeffIter = PtrIter<std::uint64_t *>; 313 314 using ConstCoeffIter = PtrIter<const std::uint64_t *>; 315 316 using ConstModulusIter = PtrIter<const Modulus *>; 317 318 using ConstNTTTablesIter = PtrIter<const NTTTables *>; 319 320 using ModulusIter = PtrIter<Modulus *>; 321 322 using NTTTablesIter = PtrIter<NTTTables *>; 323 324 namespace iterator_internal 325 { 326 template <typename Enable, typename... Ts> 327 struct IterType; 328 329 template <typename T> 330 struct IterType<std::enable_if_t<std::is_arithmetic<T>::value>, T> 331 { 332 using type = SeqIter<T, void>; 333 }; 334 335 template <typename T> 336 struct IterType< 337 std::enable_if_t<std::is_base_of<SEALIterBase, std::decay_t<T>>::value && !std::is_pointer<T>::value>, 338 T> 339 { 340 using type = std::decay_t<T>; 341 }; 342 343 template <> 344 struct IterType<void, Ciphertext &> 345 { 346 using type = PolyIter; 347 }; 348 349 template <> 350 struct IterType<void, const Ciphertext &> 351 { 352 using type = ConstPolyIter; 353 }; 354 355 template <typename T> 356 struct IterType<void, const T *> 357 { 358 using type = PtrIter<const T *>; 359 }; 360 361 template <typename T> 362 struct IterType<void, T *> 363 { 364 using type = PtrIter<T *>; 365 }; 366 367 template <typename T> 368 struct IterType<void, const T *&> 369 { 370 using type = PtrIter<const T *>; 371 }; 372 373 template <typename T> 374 struct IterType<void, T *&> 375 { 376 using type = PtrIter<T *>; 377 }; 378 379 template <typename T> 380 struct IterType<void, std::vector<T> &> 381 { 382 using type = PtrIter<T *>; 383 }; 384 385 template <typename T> 386 struct IterType<void, const std::vector<T> &> 387 { 388 using type = PtrIter<const T *>; 389 }; 390 391 template <typename T> 392 struct IterType<void, Pointer<T> &> 393 { 394 using type = PtrIter<T *>; 395 }; 396 397 template <typename T> 398 struct IterType<void, const Pointer<T> &> 399 { 400 using type = PtrIter<T *>; 401 }; 402 403 template <typename T> 404 struct IterType<void, ConstPointer<T> &> 405 { 406 using type = PtrIter<const T *>; 407 }; 408 409 template <typename T> 410 struct IterType<void, const ConstPointer<T> &> 411 { 412 using type = PtrIter<const T *>; 413 }; 414 } // namespace iterator_internal 415 416 template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>> 417 class SeqIter : public SEALIterBase 418 { 419 public: 420 using self_type = SeqIter; 421 422 // Standard iterator typedefs 423 using value_type = T; 424 using pointer = void; 425 using reference = const value_type &; 426 using iterator_category = std::random_access_iterator_tag; 427 using difference_type = std::ptrdiff_t; 428 429 SeqIter() = default; 430 431 SeqIter(T start) : value_(start) 432 {} 433 434 SeqIter(const self_type ©) = default; 435 436 self_type &operator=(const self_type &assign) = default; 437 438 SEAL_NODISCARD inline reference operator*() const noexcept 439 { 440 return value_; 441 } 442 443 template <typename SizeT> 444 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 445 { 446 return value_ + static_cast<T>(n); 447 } 448 449 inline self_type &operator++() noexcept 450 { 451 value_++; 452 return *this; 453 } 454 455 inline self_type operator++(int) noexcept 456 { 457 self_type result(value_); 458 value_++; 459 return result; 460 } 461 462 inline self_type &operator--() noexcept 463 { 464 value_--; 465 return *this; 466 } 467 468 inline self_type operator--(int) noexcept 469 { 470 self_type result(value_); 471 value_--; 472 return result; 473 } 474 475 template <typename SizeT> 476 inline self_type &operator+=(SizeT n) noexcept 477 { 478 value_ += static_cast<T>(n); 479 return *this; 480 } 481 482 template <typename SizeT> 483 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 484 { 485 return value_ + static_cast<T>(n); 486 } 487 488 template <typename SizeT> 489 inline self_type &operator-=(SizeT n) noexcept 490 { 491 value_ -= static_cast<T>(n); 492 return *this; 493 } 494 495 template <typename SizeT> 496 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 497 { 498 return value_ - static_cast<T>(n); 499 } 500 501 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const noexcept 502 { 503 return static_cast<difference_type>(value_) - static_cast<difference_type>(b.value_); 504 } 505 506 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 507 { 508 return value_ == *compare; 509 } 510 511 template <typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>> 512 SEAL_NODISCARD inline bool operator==(S compare) const noexcept 513 { 514 return value_ == compare; 515 } 516 517 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 518 { 519 return !(*this == compare); 520 } 521 522 template <typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>> 523 SEAL_NODISCARD inline bool operator!=(S compare) const noexcept 524 { 525 return !(*this == compare); 526 } 527 528 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 529 { 530 return value_ < *compare; 531 } 532 533 template <typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>> 534 SEAL_NODISCARD inline bool operator<(S compare) const noexcept 535 { 536 return value_ < compare; 537 } 538 539 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 540 { 541 return value_ > *compare; 542 } 543 544 template <typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>> 545 SEAL_NODISCARD inline bool operator>(S compare) const noexcept 546 { 547 return value_ > compare; 548 } 549 550 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 551 { 552 return !(value_ > *compare); 553 } 554 555 template <typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>> 556 SEAL_NODISCARD inline bool operator<=(S compare) const noexcept 557 { 558 return !(value_ > compare); 559 } 560 561 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 562 { 563 return !(value_ < *compare); 564 } 565 566 template <typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>> 567 SEAL_NODISCARD inline bool operator>=(S compare) const noexcept 568 { 569 return !(value_ < compare); 570 } 571 572 SEAL_NODISCARD inline operator T() const noexcept 573 { 574 return value_; 575 } 576 577 private: 578 T value_ = 0; 579 }; 580 581 template <typename T> 582 SEAL_NODISCARD inline auto seq_iter(T value = 0) -> SeqIter<T> 583 { 584 return value; 585 } 586 587 template <typename T> 588 class PtrIter<T *> : public SEALIterBase 589 { 590 public: 591 using self_type = PtrIter<T *>; 592 593 // Standard iterator typedefs 594 using value_type = T &; 595 using pointer = T *; 596 using reference = value_type; 597 using iterator_category = std::random_access_iterator_tag; 598 using difference_type = std::ptrdiff_t; 599 600 PtrIter() = default; 601 602 template <typename S> 603 PtrIter(S *ptr) noexcept : ptr_(ptr) 604 {} 605 606 template <typename S> 607 PtrIter(PtrIter<S *> copy) noexcept : ptr_(copy.ptr()) 608 {} 609 610 template <typename S> 611 PtrIter(std::vector<S> &arr) noexcept : PtrIter(arr.data()) 612 {} 613 614 template <typename S> 615 PtrIter(const std::vector<S> &arr) noexcept : PtrIter(arr.data()) 616 {} 617 618 template <typename S> 619 PtrIter(const Pointer<S> &arr) noexcept : PtrIter(arr.get()) 620 {} 621 622 template <typename S> 623 inline self_type &operator=(const PtrIter<S *> &assign) noexcept 624 { 625 ptr_ = assign.ptr(); 626 return *this; 627 } 628 629 SEAL_NODISCARD inline reference operator*() const noexcept 630 { 631 return *ptr_; 632 } 633 634 template <typename SizeT> 635 SEAL_NODISCARD inline reference operator[](SizeT n) const noexcept 636 { 637 return ptr_[n]; 638 } 639 640 inline self_type &operator++() noexcept 641 { 642 ptr_++; 643 return *this; 644 } 645 646 inline self_type operator++(int) noexcept 647 { 648 self_type result(ptr_); 649 ptr_++; 650 return result; 651 } 652 653 inline self_type &operator--() noexcept 654 { 655 ptr_--; 656 return *this; 657 } 658 659 inline self_type operator--(int) noexcept 660 { 661 self_type result(ptr_); 662 ptr_--; 663 return result; 664 } 665 666 template <typename SizeT> 667 inline self_type &operator+=(SizeT n) noexcept 668 { 669 ptr_ += n; 670 return *this; 671 } 672 673 template <typename SizeT> 674 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 675 { 676 return ptr_ + n; 677 } 678 679 template <typename SizeT> 680 inline self_type &operator-=(SizeT n) noexcept 681 { 682 ptr_ -= n; 683 return *this; 684 } 685 686 template <typename SizeT> 687 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 688 { 689 return ptr_ - n; 690 } 691 692 template <typename S> 693 SEAL_NODISCARD inline difference_type operator-(const PtrIter<S *> &b) const noexcept 694 { 695 return std::distance(b.ptr(), ptr_); 696 } 697 698 template <typename S> 699 SEAL_NODISCARD inline bool operator==(const PtrIter<S *> &compare) const noexcept 700 { 701 return ptr_ == compare.ptr(); 702 } 703 704 template <typename S> 705 SEAL_NODISCARD inline bool operator!=(const PtrIter<S *> &compare) const noexcept 706 { 707 return !(*this == compare); 708 } 709 710 template <typename S> 711 SEAL_NODISCARD inline bool operator<(const PtrIter<S *> &compare) const noexcept 712 { 713 return ptr_ < compare.ptr(); 714 } 715 716 template <typename S> 717 SEAL_NODISCARD inline bool operator>(const PtrIter<S *> &compare) const noexcept 718 { 719 return ptr_ > compare.ptr(); 720 } 721 722 template <typename S> 723 SEAL_NODISCARD inline bool operator<=(const PtrIter<S *> &compare) const noexcept 724 { 725 return !(ptr_ > compare.ptr()); 726 } 727 728 template <typename S> 729 SEAL_NODISCARD inline bool operator>=(const PtrIter<S *> &compare) const noexcept 730 { 731 return !(ptr_ < compare.ptr()); 732 } 733 734 SEAL_NODISCARD explicit inline operator bool() const noexcept 735 { 736 return nullptr != ptr_; 737 } 738 739 SEAL_NODISCARD inline reference operator->() const noexcept 740 { 741 return **this; 742 } 743 744 SEAL_NODISCARD inline pointer ptr() const noexcept 745 { 746 return ptr_; 747 } 748 749 SEAL_NODISCARD inline operator pointer() const noexcept 750 { 751 return ptr_; 752 } 753 754 private: 755 pointer ptr_ = nullptr; 756 }; 757 758 template <typename T> 759 class StrideIter<T *> : public SEALIterBase 760 { 761 public: 762 using self_type = StrideIter; 763 764 // Standard iterator typedefs 765 using value_type = PtrIter<T *>; 766 using pointer = T *; 767 using reference = const value_type &; 768 using iterator_category = std::random_access_iterator_tag; 769 using difference_type = std::ptrdiff_t; 770 771 StrideIter() = default; 772 773 template <typename S> 774 StrideIter(S *ptr, std::size_t stride) noexcept : ptr_it_(ptr), stride_(stride) 775 {} 776 777 template <typename S> 778 StrideIter(StrideIter<S *> copy) noexcept : ptr_it_(copy.ptr()), stride_(copy.stride()) 779 {} 780 781 template <typename S> 782 StrideIter(std::vector<S> &arr, std::size_t stride) noexcept : StrideIter(arr.data(), stride) 783 {} 784 785 template <typename S> 786 StrideIter(const std::vector<S> &arr, std::size_t stride) noexcept : StrideIter(arr.data(), stride) 787 {} 788 789 template <typename S> 790 StrideIter(const Pointer<S> &arr, std::size_t stride) noexcept : StrideIter(arr.get(), stride) 791 {} 792 793 template <typename S> 794 inline self_type &operator=(const StrideIter<S *> &assign) noexcept 795 { 796 ptr_it_ = assign.ptr(); 797 stride_ = assign.stride(); 798 return *this; 799 } 800 801 SEAL_NODISCARD inline reference operator*() const noexcept 802 { 803 return ptr_it_; 804 } 805 806 template <typename SizeT> 807 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 808 { 809 self_type result(*this); 810 result += static_cast<difference_type>(n); 811 return *result; 812 } 813 814 inline self_type &operator++() noexcept 815 { 816 ptr_it_ += static_cast<difference_type>(stride_); 817 return *this; 818 } 819 820 inline self_type operator++(int) noexcept 821 { 822 self_type result(*this); 823 ptr_it_ += static_cast<difference_type>(stride_); 824 return result; 825 } 826 827 inline self_type &operator--() noexcept 828 { 829 ptr_it_ -= static_cast<difference_type>(stride_); 830 return *this; 831 } 832 833 inline self_type operator--(int) noexcept 834 { 835 self_type result(*this); 836 ptr_it_ -= static_cast<difference_type>(stride_); 837 return result; 838 } 839 840 template <typename SizeT> 841 inline self_type &operator+=(SizeT n) noexcept 842 { 843 ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(stride_); 844 return *this; 845 } 846 847 template <typename SizeT> 848 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 849 { 850 self_type result(*this); 851 result.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(stride_); 852 return result; 853 } 854 855 template <typename SizeT> 856 inline self_type &operator-=(SizeT n) noexcept 857 { 858 ptr_it_ -= static_cast<difference_type>(n) * static_cast<difference_type>(stride_); 859 return *this; 860 } 861 862 template <typename SizeT> 863 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 864 { 865 return *this + (-static_cast<difference_type>(n)); 866 } 867 868 template <typename S> 869 SEAL_NODISCARD inline difference_type operator-(const StrideIter<S *> &b) const 870 { 871 #ifdef SEAL_DEBUG 872 if (!stride_) 873 { 874 throw std::logic_error("stride cannot be zero"); 875 } 876 if (stride_ != b.stride()) 877 { 878 throw std::invalid_argument("incompatible iterators"); 879 } 880 #endif 881 return (ptr_it_ - *b) / static_cast<difference_type>(stride_); 882 } 883 884 template <typename S> 885 SEAL_NODISCARD inline bool operator==(const StrideIter<S *> &compare) const noexcept 886 { 887 return ptr_it_ == *compare; 888 } 889 890 template <typename S> 891 SEAL_NODISCARD inline bool operator!=(const StrideIter<S *> &compare) const noexcept 892 { 893 return !(*this == compare); 894 } 895 896 template <typename S> 897 SEAL_NODISCARD inline bool operator<(const StrideIter<S *> &compare) const noexcept 898 { 899 return ptr_it_ < *compare; 900 } 901 902 template <typename S> 903 SEAL_NODISCARD inline bool operator>(const StrideIter<S *> &compare) const noexcept 904 { 905 return ptr_it_ > *compare; 906 } 907 908 template <typename S> 909 SEAL_NODISCARD inline bool operator<=(const StrideIter<S *> &compare) const noexcept 910 { 911 return !(ptr_it_ > *compare); 912 } 913 914 template <typename S> 915 SEAL_NODISCARD inline bool operator>=(const StrideIter<S *> &compare) const noexcept 916 { 917 return !(ptr_it_ < *compare); 918 } 919 920 SEAL_NODISCARD explicit inline operator bool() const noexcept 921 { 922 return static_cast<bool>(ptr_it_); 923 } 924 925 SEAL_NODISCARD inline reference operator->() const noexcept 926 { 927 return **this; 928 } 929 930 SEAL_NODISCARD inline std::size_t stride() const noexcept 931 { 932 return stride_; 933 } 934 935 SEAL_NODISCARD inline pointer ptr() const noexcept 936 { 937 return ptr_it_.ptr(); 938 } 939 940 SEAL_NODISCARD inline operator pointer() const noexcept 941 { 942 return ptr_it_.operator pointer(); 943 } 944 945 private: 946 PtrIter<T *> ptr_it_ = {}; 947 948 std::size_t stride_ = 0; 949 }; 950 951 class RNSIter : public SEALIterBase 952 { 953 public: 954 friend class PolyIter; 955 956 using self_type = RNSIter; 957 958 // Standard iterator typedefs 959 using value_type = CoeffIter; 960 using pointer = void; 961 using reference = const value_type &; 962 using iterator_category = std::random_access_iterator_tag; 963 using difference_type = std::ptrdiff_t; 964 965 RNSIter() : ptr_it_(), step_size_(0) 966 {} 967 968 RNSIter(std::uint64_t *ptr, std::size_t poly_modulus_degree) : ptr_it_(ptr), step_size_(poly_modulus_degree) 969 {} 970 971 RNSIter(const self_type ©) = default; 972 973 self_type &operator=(const self_type &assign) = default; 974 975 template <typename S> 976 RNSIter(const StrideIter<S *> &stride_it) : RNSIter(stride_it.ptr(), stride_it.stride()) 977 {} 978 979 template <typename S> 980 inline self_type &operator=(const StrideIter<S *> &assign) 981 { 982 ptr_it_ = assign; 983 step_size_ = assign.stride(); 984 return *this; 985 } 986 987 SEAL_NODISCARD inline reference operator*() const noexcept 988 { 989 return ptr_it_; 990 } 991 992 template <typename SizeT> 993 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 994 { 995 self_type result(*this); 996 result += static_cast<difference_type>(n); 997 return *result; 998 } 999 1000 inline self_type &operator++() noexcept 1001 { 1002 ptr_it_ += static_cast<difference_type>(step_size_); 1003 return *this; 1004 } 1005 1006 inline self_type operator++(int) noexcept 1007 { 1008 self_type result(*this); 1009 ptr_it_ += static_cast<difference_type>(step_size_); 1010 return result; 1011 } 1012 1013 inline self_type &operator--() noexcept 1014 { 1015 ptr_it_ -= static_cast<difference_type>(step_size_); 1016 return *this; 1017 } 1018 1019 inline self_type operator--(int) noexcept 1020 { 1021 self_type result(*this); 1022 ptr_it_ -= static_cast<difference_type>(step_size_); 1023 return result; 1024 } 1025 1026 template <typename SizeT> 1027 inline self_type &operator+=(SizeT n) noexcept 1028 { 1029 ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1030 return *this; 1031 } 1032 1033 template <typename SizeT> 1034 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 1035 { 1036 self_type result(*this); 1037 result.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1038 return result; 1039 } 1040 1041 template <typename SizeT> 1042 inline self_type &operator-=(SizeT n) noexcept 1043 { 1044 ptr_it_ -= static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1045 return *this; 1046 } 1047 1048 template <typename SizeT> 1049 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 1050 { 1051 return *this + (-static_cast<difference_type>(n)); 1052 } 1053 1054 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 1055 { 1056 #ifdef SEAL_DEBUG 1057 if (!step_size_) 1058 { 1059 throw std::logic_error("step_size cannot be zero"); 1060 } 1061 if (step_size_ != b.step_size_) 1062 { 1063 throw std::invalid_argument("incompatible iterators"); 1064 } 1065 #endif 1066 return (ptr_it_ - b.ptr_it_) / static_cast<difference_type>(step_size_); 1067 } 1068 1069 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 1070 { 1071 return ptr_it_ == compare.ptr_it_; 1072 } 1073 1074 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 1075 { 1076 return !(*this == compare); 1077 } 1078 1079 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 1080 { 1081 return ptr_it_ < compare.ptr_it_; 1082 } 1083 1084 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 1085 { 1086 return ptr_it_ > compare.ptr_it_; 1087 } 1088 1089 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 1090 { 1091 return !(ptr_it_ > compare.ptr_it_); 1092 } 1093 1094 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 1095 { 1096 return !(ptr_it_ < compare.ptr_it_); 1097 } 1098 1099 SEAL_NODISCARD inline operator std::uint64_t *() const noexcept 1100 { 1101 return static_cast<std::uint64_t *>(ptr_it_); 1102 } 1103 1104 SEAL_NODISCARD explicit inline operator bool() const noexcept 1105 { 1106 return static_cast<bool>(ptr_it_); 1107 } 1108 1109 SEAL_NODISCARD inline reference operator->() const noexcept 1110 { 1111 return **this; 1112 } 1113 1114 SEAL_NODISCARD inline std::size_t poly_modulus_degree() const noexcept 1115 { 1116 return step_size_; 1117 } 1118 1119 private: 1120 CoeffIter ptr_it_ = {}; 1121 1122 std::size_t step_size_ = 0; 1123 }; 1124 1125 class ConstRNSIter : public SEALIterBase 1126 { 1127 public: 1128 friend class ConstPolyIter; 1129 1130 using self_type = ConstRNSIter; 1131 1132 // Standard iterator typedefs 1133 using value_type = ConstCoeffIter; 1134 using pointer = void; 1135 using reference = const value_type &; 1136 using iterator_category = std::random_access_iterator_tag; 1137 using difference_type = std::ptrdiff_t; 1138 1139 ConstRNSIter() : ptr_it_(), step_size_(0) 1140 {} 1141 1142 ConstRNSIter(const std::uint64_t *ptr, std::size_t poly_modulus_degree) 1143 : ptr_it_(ptr), step_size_(poly_modulus_degree) 1144 {} 1145 1146 ConstRNSIter(const self_type ©) = default; 1147 1148 self_type &operator=(const self_type &assign) = default; 1149 1150 ConstRNSIter(const RNSIter ©) 1151 : ptr_it_(static_cast<const std::uint64_t *>(copy)), step_size_(copy.poly_modulus_degree()) 1152 {} 1153 1154 template <typename S> 1155 ConstRNSIter(const StrideIter<S *> &stride_it) : ConstRNSIter(stride_it.ptr(), stride_it.stride()) 1156 {} 1157 1158 template <typename S> 1159 inline self_type &operator=(const StrideIter<S *> &assign) 1160 { 1161 ptr_it_ = assign; 1162 step_size_ = assign.stride(); 1163 return *this; 1164 } 1165 1166 SEAL_NODISCARD inline reference operator*() const noexcept 1167 { 1168 return ptr_it_; 1169 } 1170 1171 template <typename SizeT> 1172 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 1173 { 1174 self_type result(*this); 1175 result += static_cast<difference_type>(n); 1176 return *result; 1177 } 1178 1179 inline self_type &operator++() noexcept 1180 { 1181 ptr_it_ += static_cast<difference_type>(step_size_); 1182 return *this; 1183 } 1184 1185 inline self_type operator++(int) noexcept 1186 { 1187 self_type result(*this); 1188 ptr_it_ += static_cast<difference_type>(step_size_); 1189 return result; 1190 } 1191 1192 inline self_type &operator--() noexcept 1193 { 1194 ptr_it_ -= static_cast<difference_type>(step_size_); 1195 return *this; 1196 } 1197 1198 inline self_type operator--(int) noexcept 1199 { 1200 self_type result(*this); 1201 ptr_it_ -= static_cast<difference_type>(step_size_); 1202 return result; 1203 } 1204 1205 template <typename SizeT> 1206 inline self_type &operator+=(SizeT n) noexcept 1207 { 1208 ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1209 return *this; 1210 } 1211 1212 template <typename SizeT> 1213 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 1214 { 1215 self_type result(*this); 1216 result.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1217 return result; 1218 } 1219 1220 template <typename SizeT> 1221 inline self_type &operator-=(SizeT n) noexcept 1222 { 1223 ptr_it_ -= static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1224 return *this; 1225 } 1226 1227 template <typename SizeT> 1228 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 1229 { 1230 return *this + (-static_cast<difference_type>(n)); 1231 } 1232 1233 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 1234 { 1235 #ifdef SEAL_DEBUG 1236 if (!step_size_) 1237 { 1238 throw std::logic_error("step_size cannot be zero"); 1239 } 1240 if (step_size_ != b.step_size_) 1241 { 1242 throw std::invalid_argument("incompatible iterators"); 1243 } 1244 #endif 1245 return (ptr_it_ - b.ptr_it_) / static_cast<difference_type>(step_size_); 1246 } 1247 1248 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 1249 { 1250 return ptr_it_ == compare.ptr_it_; 1251 } 1252 1253 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 1254 { 1255 return !(*this == compare); 1256 } 1257 1258 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 1259 { 1260 return ptr_it_ < compare.ptr_it_; 1261 } 1262 1263 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 1264 { 1265 return ptr_it_ > compare.ptr_it_; 1266 } 1267 1268 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 1269 { 1270 return !(ptr_it_ > compare.ptr_it_); 1271 } 1272 1273 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 1274 { 1275 return !(ptr_it_ < compare.ptr_it_); 1276 } 1277 1278 SEAL_NODISCARD inline operator const std::uint64_t *() const noexcept 1279 { 1280 return static_cast<const std::uint64_t *>(ptr_it_); 1281 } 1282 1283 SEAL_NODISCARD explicit inline operator bool() const noexcept 1284 { 1285 return static_cast<bool>(ptr_it_); 1286 } 1287 1288 SEAL_NODISCARD inline reference operator->() const noexcept 1289 { 1290 return **this; 1291 } 1292 1293 SEAL_NODISCARD inline std::size_t poly_modulus_degree() const noexcept 1294 { 1295 return step_size_; 1296 } 1297 1298 private: 1299 ConstCoeffIter ptr_it_ = {}; 1300 1301 std::size_t step_size_ = 0; 1302 }; 1303 1304 class PolyIter : public SEALIterBase 1305 { 1306 public: 1307 using self_type = PolyIter; 1308 1309 // Standard iterator typedefs 1310 using value_type = RNSIter; 1311 using pointer = void; 1312 using reference = const value_type &; 1313 using iterator_category = std::random_access_iterator_tag; 1314 using difference_type = std::ptrdiff_t; 1315 1316 PolyIter() : rns_it_(nullptr, 0), coeff_modulus_size_(0), step_size_(0) 1317 {} 1318 1319 PolyIter(std::uint64_t *ptr, std::size_t poly_modulus_degree, std::size_t coeff_modulus_size) 1320 : rns_it_(ptr, poly_modulus_degree), coeff_modulus_size_(coeff_modulus_size), 1321 step_size_(mul_safe(poly_modulus_degree, coeff_modulus_size_)) 1322 {} 1323 1324 PolyIter(Ciphertext &ct); 1325 1326 PolyIter(const self_type ©) = default; 1327 1328 self_type &operator=(const self_type &assign) = default; 1329 1330 SEAL_NODISCARD inline reference operator*() const noexcept 1331 { 1332 return rns_it_; 1333 } 1334 1335 template <typename SizeT> 1336 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 1337 { 1338 self_type result(*this); 1339 result += static_cast<difference_type>(n); 1340 return *result; 1341 } 1342 1343 inline self_type &operator++() noexcept 1344 { 1345 rns_it_.ptr_it_ += step_size_; 1346 return *this; 1347 } 1348 1349 inline self_type operator++(int) noexcept 1350 { 1351 self_type result(*this); 1352 rns_it_.ptr_it_ += step_size_; 1353 return result; 1354 } 1355 1356 inline self_type &operator--() noexcept 1357 { 1358 rns_it_.ptr_it_ -= step_size_; 1359 return *this; 1360 } 1361 1362 inline self_type operator--(int) noexcept 1363 { 1364 self_type result(*this); 1365 rns_it_.ptr_it_ -= step_size_; 1366 return result; 1367 } 1368 1369 template <typename SizeT> 1370 inline self_type &operator+=(SizeT n) noexcept 1371 { 1372 rns_it_.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1373 return *this; 1374 } 1375 1376 template <typename SizeT> 1377 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 1378 { 1379 self_type result(*this); 1380 result.rns_it_.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1381 return result; 1382 } 1383 1384 template <typename SizeT> 1385 inline self_type &operator-=(SizeT n) noexcept 1386 { 1387 rns_it_.ptr_it_ -= static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1388 return *this; 1389 } 1390 1391 template <typename SizeT> 1392 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 1393 { 1394 return *this + (-static_cast<difference_type>(n)); 1395 } 1396 1397 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 1398 { 1399 #ifdef SEAL_DEBUG 1400 if (!step_size_) 1401 { 1402 throw std::logic_error("step_size cannot be zero"); 1403 } 1404 if (step_size_ != b.step_size_) 1405 { 1406 throw std::invalid_argument("incompatible iterators"); 1407 } 1408 if (coeff_modulus_size_ != b.coeff_modulus_size_) 1409 { 1410 throw std::invalid_argument("incompatible iterators"); 1411 } 1412 #endif 1413 return (rns_it_.ptr_it_ - b.rns_it_.ptr_it_) / static_cast<difference_type>(step_size_); 1414 } 1415 1416 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 1417 { 1418 return rns_it_ == compare.rns_it_; 1419 } 1420 1421 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 1422 { 1423 return !(*this == compare); 1424 } 1425 1426 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 1427 { 1428 return rns_it_ < compare.rns_it_; 1429 } 1430 1431 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 1432 { 1433 return rns_it_ > compare.rns_it_; 1434 } 1435 1436 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 1437 { 1438 return !(rns_it_ > compare.rns_it_); 1439 } 1440 1441 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 1442 { 1443 return !(rns_it_ < compare.rns_it_); 1444 } 1445 1446 SEAL_NODISCARD inline operator std::uint64_t *() const noexcept 1447 { 1448 return rns_it_; 1449 } 1450 1451 SEAL_NODISCARD explicit inline operator bool() const noexcept 1452 { 1453 return static_cast<bool>(rns_it_); 1454 } 1455 1456 SEAL_NODISCARD inline reference operator->() const noexcept 1457 { 1458 return **this; 1459 } 1460 1461 SEAL_NODISCARD inline std::size_t poly_modulus_degree() const noexcept 1462 { 1463 return rns_it_.poly_modulus_degree(); 1464 } 1465 1466 SEAL_NODISCARD inline std::size_t coeff_modulus_size() const noexcept 1467 { 1468 return coeff_modulus_size_; 1469 } 1470 1471 private: 1472 RNSIter rns_it_ = {}; 1473 1474 std::size_t coeff_modulus_size_ = 0; 1475 1476 std::size_t step_size_ = 0; 1477 }; 1478 1479 class ConstPolyIter : public SEALIterBase 1480 { 1481 public: 1482 using self_type = ConstPolyIter; 1483 1484 // Standard iterator typedefs 1485 using value_type = ConstRNSIter; 1486 using pointer = void; 1487 using reference = const value_type &; 1488 using iterator_category = std::random_access_iterator_tag; 1489 using difference_type = std::ptrdiff_t; 1490 1491 ConstPolyIter() : rns_it_(nullptr, 0), coeff_modulus_size_(0), step_size_(0) 1492 {} 1493 1494 ConstPolyIter(const std::uint64_t *ptr, std::size_t poly_modulus_degree, std::size_t coeff_modulus_size) 1495 : rns_it_(ptr, poly_modulus_degree), coeff_modulus_size_(coeff_modulus_size), 1496 step_size_(mul_safe(poly_modulus_degree, coeff_modulus_size_)) 1497 {} 1498 1499 ConstPolyIter(const Ciphertext &ct); 1500 1501 ConstPolyIter(Ciphertext &ct); 1502 1503 ConstPolyIter(const self_type ©) = default; 1504 1505 self_type &operator=(const self_type &assign) = default; 1506 1507 ConstPolyIter(const PolyIter ©) 1508 : rns_it_(static_cast<const std::uint64_t *>(copy), copy.poly_modulus_degree()), 1509 coeff_modulus_size_(copy.coeff_modulus_size()), 1510 step_size_(mul_safe(rns_it_.poly_modulus_degree(), coeff_modulus_size_)) 1511 {} 1512 1513 SEAL_NODISCARD inline reference operator*() const noexcept 1514 { 1515 return rns_it_; 1516 } 1517 1518 template <typename SizeT> 1519 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 1520 { 1521 self_type result(*this); 1522 result += static_cast<difference_type>(n); 1523 return *result; 1524 } 1525 1526 inline self_type &operator++() noexcept 1527 { 1528 rns_it_.ptr_it_ += step_size_; 1529 return *this; 1530 } 1531 1532 inline self_type operator++(int) noexcept 1533 { 1534 self_type result(*this); 1535 rns_it_.ptr_it_ += step_size_; 1536 return result; 1537 } 1538 1539 inline self_type &operator--() noexcept 1540 { 1541 rns_it_.ptr_it_ -= step_size_; 1542 return *this; 1543 } 1544 1545 inline self_type operator--(int) noexcept 1546 { 1547 self_type result(*this); 1548 rns_it_.ptr_it_ -= step_size_; 1549 return result; 1550 } 1551 1552 template <typename SizeT> 1553 inline self_type &operator+=(SizeT n) noexcept 1554 { 1555 rns_it_.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1556 return *this; 1557 } 1558 1559 template <typename SizeT> 1560 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 1561 { 1562 self_type result(*this); 1563 result.rns_it_.ptr_it_ += static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1564 return result; 1565 } 1566 1567 template <typename SizeT> 1568 inline self_type &operator-=(SizeT n) noexcept 1569 { 1570 rns_it_.ptr_it_ -= static_cast<difference_type>(n) * static_cast<difference_type>(step_size_); 1571 return *this; 1572 } 1573 1574 template <typename SizeT> 1575 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 1576 { 1577 return *this + (-static_cast<difference_type>(n)); 1578 } 1579 1580 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 1581 { 1582 #ifdef SEAL_DEBUG 1583 if (!step_size_) 1584 { 1585 throw std::logic_error("step_size cannot be zero"); 1586 } 1587 if (step_size_ != b.step_size_) 1588 { 1589 throw std::invalid_argument("incompatible iterators"); 1590 } 1591 if (coeff_modulus_size_ != b.coeff_modulus_size_) 1592 { 1593 throw std::invalid_argument("incompatible iterators"); 1594 } 1595 #endif 1596 return (rns_it_.ptr_it_ - b.rns_it_.ptr_it_) / static_cast<difference_type>(step_size_); 1597 } 1598 1599 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 1600 { 1601 return rns_it_ == compare.rns_it_; 1602 } 1603 1604 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 1605 { 1606 return !(*this == compare); 1607 } 1608 1609 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 1610 { 1611 return rns_it_ < compare.rns_it_; 1612 } 1613 1614 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 1615 { 1616 return rns_it_ > compare.rns_it_; 1617 } 1618 1619 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 1620 { 1621 return !(rns_it_ > compare.rns_it_); 1622 } 1623 1624 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 1625 { 1626 return !(rns_it_ < compare.rns_it_); 1627 } 1628 1629 SEAL_NODISCARD inline operator const std::uint64_t *() const noexcept 1630 { 1631 return rns_it_; 1632 } 1633 1634 SEAL_NODISCARD explicit inline operator bool() const noexcept 1635 { 1636 return static_cast<bool>(rns_it_); 1637 } 1638 1639 SEAL_NODISCARD inline reference operator->() const noexcept 1640 { 1641 return **this; 1642 } 1643 1644 SEAL_NODISCARD inline std::size_t poly_modulus_degree() const noexcept 1645 { 1646 return rns_it_.poly_modulus_degree(); 1647 } 1648 1649 SEAL_NODISCARD inline std::size_t coeff_modulus_size() const noexcept 1650 { 1651 return coeff_modulus_size_; 1652 } 1653 1654 private: 1655 ConstRNSIter rns_it_ = {}; 1656 1657 std::size_t coeff_modulus_size_ = 0; 1658 1659 std::size_t step_size_ = 0; 1660 }; 1661 1662 template <typename SEALIter> 1663 class ReverseIter : public SEALIter 1664 { 1665 public: 1666 static_assert( 1667 std::is_base_of<SEALIterBase, SEALIter>::value, 1668 "Template parameter must derive from seal::util::SEALIterBase"); 1669 1670 using self_type = ReverseIter<SEALIter>; 1671 1672 // Standard iterator typedefs 1673 using value_type = typename std::iterator_traits<SEALIter>::value_type; 1674 using pointer = typename std::iterator_traits<SEALIter>::pointer; 1675 using reference = typename std::iterator_traits<SEALIter>::reference; 1676 using iterator_category = typename std::iterator_traits<SEALIter>::iterator_category; 1677 using difference_type = typename std::iterator_traits<SEALIter>::difference_type; 1678 1679 ReverseIter() : SEALIter() 1680 {} 1681 1682 ReverseIter(const SEALIter ©) : SEALIter(copy) 1683 {} 1684 1685 ReverseIter(const self_type ©) = default; 1686 1687 self_type &operator=(const self_type &assign) = default; 1688 1689 template <typename SizeT> 1690 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 1691 { 1692 self_type result(*this); 1693 result += static_cast<difference_type>(n); 1694 return *result; 1695 } 1696 1697 inline self_type &operator++() noexcept 1698 { 1699 SEALIter::operator--(); 1700 return *this; 1701 } 1702 1703 inline self_type operator++(int) noexcept 1704 { 1705 self_type result(*this); 1706 SEALIter::operator--(); 1707 return result; 1708 } 1709 1710 inline self_type &operator--() noexcept 1711 { 1712 SEALIter::operator++(); 1713 return *this; 1714 } 1715 1716 inline self_type operator--(int) noexcept 1717 { 1718 self_type result(*this); 1719 SEALIter::operator++(); 1720 return result; 1721 } 1722 1723 template <typename SizeT> 1724 inline self_type &operator+=(SizeT n) noexcept 1725 { 1726 SEALIter::operator-=(n); 1727 return *this; 1728 } 1729 1730 template <typename SizeT> 1731 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 1732 { 1733 self_type result(*this); 1734 result += n; 1735 return result; 1736 } 1737 1738 template <typename SizeT> 1739 inline self_type &operator-=(SizeT n) noexcept 1740 { 1741 SEALIter::operator+=(n); 1742 return *this; 1743 } 1744 1745 template <typename SizeT> 1746 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 1747 { 1748 return *this + (-static_cast<difference_type>(n)); 1749 } 1750 1751 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 1752 { 1753 // Note the reversed order 1754 return static_cast<SEALIter>(*b) - static_cast<SEALIter>(*this); 1755 } 1756 1757 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 1758 { 1759 // Note the reversed order 1760 return static_cast<SEALIter>(*this) > static_cast<SEALIter>(*compare); 1761 } 1762 1763 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 1764 { 1765 // Note the reversed order 1766 return static_cast<SEALIter>(*this) < static_cast<SEALIter>(*compare); 1767 } 1768 1769 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 1770 { 1771 // Note the reversed order 1772 return !(*this > compare); 1773 } 1774 1775 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 1776 { 1777 return !(*this < compare); 1778 } 1779 1780 SEAL_NODISCARD inline reference operator->() const noexcept 1781 { 1782 return **this; 1783 } 1784 }; 1785 1786 namespace iterator_internal 1787 { 1788 template <typename... SEALIters> 1789 struct extend_iter_tuple; 1790 1791 template <typename SEALIter, typename... Rest> 1792 struct extend_iter_tuple<SEALIter, IterTuple<Rest...>> 1793 { 1794 using type = IterTuple<SEALIter, Rest...>; 1795 }; 1796 1797 template <typename SEALIter1, typename SEALIter2> 1798 struct extend_iter_tuple<SEALIter1, SEALIter2> 1799 { 1800 using type = IterTuple<SEALIter1, SEALIter2>; 1801 }; 1802 1803 template <typename... Ts> 1804 struct extend_std_tuple; 1805 1806 template <typename T, typename... Rest> 1807 struct extend_std_tuple<T, std::tuple<Rest...>> 1808 { 1809 using type = std::tuple<T, Rest...>; 1810 }; 1811 1812 template <typename T1, typename T2> 1813 struct extend_std_tuple<T1, T2> 1814 { 1815 using type = std::tuple<T1, T2>; 1816 }; 1817 } // namespace iterator_internal 1818 1819 template <typename SEALIter, typename... Rest> 1820 class IterTuple<SEALIter, Rest...> : public SEALIterBase 1821 { 1822 public: 1823 static_assert( 1824 std::is_base_of<SEALIterBase, SEALIter>::value, 1825 "Template parameter must derive from seal::util::SEALIterBase"); 1826 1827 using self_type = IterTuple<SEALIter, Rest...>; 1828 1829 // Standard iterator typedefs 1830 using value_type = typename iterator_internal::extend_std_tuple< 1831 typename std::iterator_traits<SEALIter>::value_type, 1832 typename std::iterator_traits<IterTuple<Rest...>>::value_type>::type; 1833 using pointer = void; 1834 using reference = const value_type &; 1835 using iterator_category = std::random_access_iterator_tag; 1836 using difference_type = std::ptrdiff_t; 1837 1838 IterTuple() = default; 1839 1840 IterTuple(SEALIter first, IterTuple<Rest...> rest) : first_(first), rest_(rest){}; 1841 1842 IterTuple(SEALIter first, Rest... rest) : first_(first), rest_(rest...) 1843 {} 1844 1845 template <typename... Ts> 1846 IterTuple(const std::tuple<Ts...> &tp) 1847 : IterTuple(seal_apply( 1848 [](auto &&... args) -> IterTuple { return { std::forward<decltype(args)>(args)... }; }, 1849 std::forward<decltype(tp)>(tp))) 1850 { 1851 static_assert( 1852 sizeof...(Ts) == sizeof...(Rest) + 1, "std::tuple size does not match seal::util::IterTuple size"); 1853 } 1854 1855 template <typename... Ts> 1856 IterTuple(std::tuple<Ts...> &&tp) 1857 : IterTuple(seal_apply( 1858 [](auto &&... args) -> IterTuple && { return { std::forward<decltype(args)>(args)... }; }, 1859 std::forward<decltype(tp)>(tp))) 1860 { 1861 static_assert( 1862 sizeof...(Ts) == sizeof...(Rest) + 1, "std::tuple size does not match seal::util::IterTuple size"); 1863 } 1864 1865 IterTuple(const self_type ©) = default; 1866 1867 self_type &operator=(const self_type &assign) = default; 1868 1869 SEAL_NODISCARD inline value_type operator*() const noexcept 1870 { 1871 return seal_apply( 1872 [this](auto &&... args) -> value_type { 1873 return { *first_, std::forward<decltype(args)>(args)... }; 1874 }, 1875 *rest_); 1876 } 1877 1878 template <typename SizeT> 1879 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 1880 { 1881 self_type result(*this); 1882 result += static_cast<difference_type>(n); 1883 return *result; 1884 } 1885 1886 inline self_type &operator++() noexcept 1887 { 1888 first_++; 1889 rest_++; 1890 return *this; 1891 } 1892 1893 inline self_type operator++(int) noexcept 1894 { 1895 self_type result(*this); 1896 first_++; 1897 rest_++; 1898 return result; 1899 } 1900 1901 inline self_type &operator--() noexcept 1902 { 1903 first_--; 1904 rest_--; 1905 return *this; 1906 } 1907 1908 inline self_type operator--(int) noexcept 1909 { 1910 self_type result(*this); 1911 first_--; 1912 rest_--; 1913 return result; 1914 } 1915 1916 template <typename SizeT> 1917 inline self_type &operator+=(SizeT n) noexcept 1918 { 1919 first_ += n; 1920 rest_ += n; 1921 return *this; 1922 } 1923 1924 template <typename SizeT> 1925 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 1926 { 1927 self_type result(*this); 1928 result += n; 1929 return result; 1930 } 1931 1932 template <typename SizeT> 1933 inline self_type &operator-=(SizeT n) noexcept 1934 { 1935 first_ -= n; 1936 rest_ -= n; 1937 return *this; 1938 } 1939 1940 template <typename SizeT> 1941 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 1942 { 1943 return *this + (-static_cast<difference_type>(n)); 1944 } 1945 1946 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 1947 { 1948 auto first = first_ - b.first_; 1949 #ifdef SEAL_DEBUG 1950 auto rest = rest_ - b.rest_; 1951 if (first != rest) 1952 { 1953 throw std::invalid_argument("incompatible iterators"); 1954 } 1955 #endif 1956 return first; 1957 } 1958 1959 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 1960 { 1961 return (first_ == compare.first_) && (rest_ == compare.rest_); 1962 } 1963 1964 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 1965 { 1966 return !(*this == compare); 1967 } 1968 1969 SEAL_NODISCARD inline bool operator<(const self_type &compare) const 1970 { 1971 auto first = first_ < compare.first_; 1972 #ifdef SEAL_DEBUG 1973 auto rest = rest_ < compare.rest_; 1974 if (first != rest) 1975 { 1976 throw std::invalid_argument("incompatible iterators"); 1977 } 1978 #endif 1979 return first; 1980 } 1981 1982 SEAL_NODISCARD inline bool operator>(const self_type &compare) const 1983 { 1984 auto first = first_ > compare.first_; 1985 #ifdef SEAL_DEBUG 1986 auto rest = rest_ > compare.rest_; 1987 if (first != rest) 1988 { 1989 throw std::invalid_argument("incompatible iterators"); 1990 } 1991 #endif 1992 return first; 1993 } 1994 1995 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const 1996 { 1997 auto first = !(first_ > compare.first_); 1998 #ifdef SEAL_DEBUG 1999 auto rest = !(rest_ > compare.rest_); 2000 if (first != rest) 2001 { 2002 throw std::invalid_argument("incompatible iterators"); 2003 } 2004 #endif 2005 return first; 2006 } 2007 2008 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const 2009 { 2010 auto first = !(first_ < compare.first_); 2011 #ifdef SEAL_DEBUG 2012 auto rest = !(rest_ < compare.rest_); 2013 if (first != rest) 2014 { 2015 throw std::invalid_argument("incompatible iterators"); 2016 } 2017 #endif 2018 return first; 2019 } 2020 2021 SEAL_NODISCARD explicit inline operator bool() const noexcept 2022 { 2023 return static_cast<bool>(first_) && static_cast<bool>(rest_); 2024 } 2025 2026 SEAL_NODISCARD inline value_type operator->() const noexcept 2027 { 2028 return **this; 2029 } 2030 2031 SEAL_NODISCARD inline const SEALIter &first() const noexcept 2032 { 2033 return first_; 2034 } 2035 2036 SEAL_NODISCARD inline const IterTuple<Rest...> &rest() const noexcept 2037 { 2038 return rest_; 2039 } 2040 2041 private: 2042 SEALIter first_ = {}; 2043 2044 IterTuple<Rest...> rest_ = {}; 2045 }; 2046 2047 template <typename SEALIter> 2048 class IterTuple<SEALIter> : public SEALIterBase 2049 { 2050 public: 2051 static_assert( 2052 std::is_base_of<SEALIterBase, SEALIter>::value, 2053 "Template parameter must derive from seal::util::SEALIterBase"); 2054 2055 using self_type = IterTuple<SEALIter>; 2056 2057 // Standard iterator typedefs 2058 using value_type = std::tuple<typename std::iterator_traits<SEALIter>::value_type>; 2059 using pointer = void; 2060 using reference = const value_type &; 2061 using iterator_category = std::random_access_iterator_tag; 2062 using difference_type = std::ptrdiff_t; 2063 2064 IterTuple(){}; 2065 2066 IterTuple(SEALIter first) : first_(first) 2067 {} 2068 2069 template <typename T> 2070 IterTuple(const std::tuple<T> &tp) : IterTuple(std::get<0>(std::forward<decltype(tp)>(tp))) 2071 {} 2072 2073 template <typename T> 2074 IterTuple(std::tuple<T> &&tp) : IterTuple(std::get<0>(std::forward<decltype(tp)>(tp))) 2075 {} 2076 2077 IterTuple(const self_type ©) = default; 2078 2079 self_type &operator=(const self_type &assign) = default; 2080 2081 SEAL_NODISCARD inline value_type operator*() const noexcept 2082 { 2083 return *first_; 2084 } 2085 2086 template <typename SizeT> 2087 SEAL_NODISCARD inline value_type operator[](SizeT n) const noexcept 2088 { 2089 self_type result(*this); 2090 result += static_cast<difference_type>(n); 2091 return *result; 2092 } 2093 2094 inline self_type &operator++() noexcept 2095 { 2096 first_++; 2097 return *this; 2098 } 2099 2100 inline self_type operator++(int) noexcept 2101 { 2102 self_type result(*this); 2103 first_++; 2104 return result; 2105 } 2106 2107 inline self_type &operator--() noexcept 2108 { 2109 first_--; 2110 return *this; 2111 } 2112 2113 inline self_type operator--(int) noexcept 2114 { 2115 self_type result(*this); 2116 first_--; 2117 return result; 2118 } 2119 2120 template <typename SizeT> 2121 inline self_type &operator+=(SizeT n) noexcept 2122 { 2123 first_ += n; 2124 return *this; 2125 } 2126 2127 template <typename SizeT> 2128 SEAL_NODISCARD inline self_type operator+(SizeT n) const noexcept 2129 { 2130 self_type result(*this); 2131 result += n; 2132 return result; 2133 } 2134 2135 template <typename SizeT> 2136 inline self_type &operator-=(SizeT n) noexcept 2137 { 2138 first_ -= n; 2139 return *this; 2140 } 2141 2142 template <typename SizeT> 2143 SEAL_NODISCARD inline self_type operator-(SizeT n) const noexcept 2144 { 2145 return *this + (-static_cast<difference_type>(n)); 2146 } 2147 2148 SEAL_NODISCARD inline difference_type operator-(const self_type &b) const 2149 { 2150 return first_ - b.first_; 2151 } 2152 2153 SEAL_NODISCARD inline bool operator==(const self_type &compare) const noexcept 2154 { 2155 return first_ == compare.first_; 2156 } 2157 2158 SEAL_NODISCARD inline bool operator!=(const self_type &compare) const noexcept 2159 { 2160 return !(*this == compare); 2161 } 2162 2163 SEAL_NODISCARD inline bool operator<(const self_type &compare) const noexcept 2164 { 2165 return first_ < compare.first_; 2166 } 2167 2168 SEAL_NODISCARD inline bool operator>(const self_type &compare) const noexcept 2169 { 2170 return first_ > compare.first_; 2171 } 2172 2173 SEAL_NODISCARD inline bool operator<=(const self_type &compare) const noexcept 2174 { 2175 return !(first_ > compare.first_); 2176 } 2177 2178 SEAL_NODISCARD inline bool operator>=(const self_type &compare) const noexcept 2179 { 2180 return !(first_ < compare.first_); 2181 } 2182 2183 SEAL_NODISCARD explicit inline operator bool() const noexcept 2184 { 2185 return static_cast<bool>(first_); 2186 } 2187 2188 SEAL_NODISCARD inline reference operator->() const noexcept 2189 { 2190 return **this; 2191 } 2192 2193 SEAL_NODISCARD inline const SEALIter &first() const noexcept 2194 { 2195 return first_; 2196 } 2197 2198 private: 2199 SEALIter first_ = {}; 2200 }; 2201 2202 // Out-of-class operator+ for all SEAL iterators 2203 template < 2204 typename SizeT, typename SEALIter, 2205 typename = std::enable_if_t<std::is_base_of<SEALIterBase, SEALIter>::value>> 2206 SEAL_NODISCARD inline SEALIter operator+(SizeT n, SEALIter it) 2207 { 2208 return it + n; 2209 } 2210 2211 namespace iterator_internal 2212 { 2213 template <std::size_t N> 2214 struct GetHelperStruct 2215 { 2216 template <typename SEALIter, typename... Rest> 2217 SEAL_NODISCARD static auto Apply(const IterTuple<SEALIter, Rest...> &it) noexcept 2218 { 2219 return GetHelperStruct<N - 1>::Apply(it.rest()); 2220 } 2221 }; 2222 2223 template <> 2224 struct GetHelperStruct<0> 2225 { 2226 template <typename SEALIter, typename... Rest> 2227 SEAL_NODISCARD static auto Apply(const IterTuple<SEALIter, Rest...> &it) noexcept 2228 { 2229 return it.first(); 2230 } 2231 }; 2232 2233 template <std::size_t N, typename... SEALIters> 2234 SEAL_NODISCARD inline auto get(const IterTuple<SEALIters...> &it) noexcept 2235 { 2236 static_assert(N < sizeof...(SEALIters), "seal::util::IterTuple index out of range"); 2237 return iterator_internal::GetHelperStruct<N>::Apply(it); 2238 } 2239 2240 template <typename T, typename... Rest> 2241 struct IterType< 2242 seal_void_t< 2243 std::enable_if_t<(sizeof...(Rest) > 0)>, typename IterType<void, T>::type, 2244 typename IterType<void, Rest...>::type>, 2245 T, Rest...> 2246 { 2247 using type = typename extend_iter_tuple< 2248 typename IterType<void, T>::type, typename IterType<void, Rest...>::type>::type; 2249 }; 2250 2251 template <typename... Ts> 2252 struct IterType<void, const std::tuple<Ts...> &> 2253 { 2254 using type = typename IterType<void, Ts...>::type; 2255 }; 2256 2257 template <typename... Ts> 2258 struct IterType<void, std::tuple<Ts...> &> 2259 { 2260 using type = typename IterType<void, Ts...>::type; 2261 }; 2262 } // namespace iterator_internal 2263 2264 template < 2265 std::size_t N, std::size_t... Rest, typename... SEALIters, typename = std::enable_if_t<sizeof...(Rest)>> 2266 SEAL_NODISCARD inline auto get(const IterTuple<SEALIters...> &it) noexcept 2267 { 2268 return get<Rest...>(iterator_internal::get<N>(it)); 2269 } 2270 2271 template <std::size_t N, typename... SEALIters> 2272 SEAL_NODISCARD inline auto get(const IterTuple<SEALIters...> &it) noexcept 2273 { 2274 return iterator_internal::get<N>(it); 2275 } 2276 2277 template <std::size_t N, std::size_t... Rest, typename... Ts, typename = std::enable_if_t<sizeof...(Rest)>> 2278 SEAL_NODISCARD inline auto get(const std::tuple<Ts...> &tp) noexcept 2279 { 2280 return get<Rest...>(std::get<N>(tp)); 2281 } 2282 2283 template <typename... Ts> 2284 SEAL_NODISCARD inline auto iter(Ts &&... ts) noexcept -> typename iterator_internal::IterType<void, Ts...>::type 2285 { 2286 return { std::forward<Ts>(ts)... }; 2287 } 2288 2289 template <typename... Ts> 2290 SEAL_NODISCARD inline auto reverse_iter(Ts &&... ts) noexcept 2291 -> ReverseIter<typename iterator_internal::IterType<void, Ts...>::type> 2292 { 2293 return typename iterator_internal::IterType<void, Ts...>::type(std::forward<Ts>(ts)...); 2294 } 2295 } // namespace util 2296 } // namespace seal 2297