types.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. #ifndef __OBLIVDS_TYPES_HPP__
  2. #define __OBLIVDS_TYPES_HPP__
  3. #include <tuple>
  4. #include <vector>
  5. #include <array>
  6. #include <cstdint>
  7. #include <x86intrin.h> // SSE and AVX intrinsics
  8. #include <bsd/stdlib.h> // arc4random_buf
  9. // The number of bits in an MPC secret-shared memory word
  10. #ifndef VALUE_BITS
  11. #define VALUE_BITS 64
  12. #endif
  13. // Values in MPC secret-shared memory are of this type.
  14. // This is the type of the underlying shared value, not the types of the
  15. // shares themselves.
  16. #if VALUE_BITS == 64
  17. using value_t = uint64_t;
  18. #elif VALUE_BITS == 32
  19. using value_t = uint32_t;
  20. #else
  21. #error "Unsupported value of VALUE_BITS"
  22. #endif
  23. // Secret-shared bits are of this type. Note that it is standards
  24. // compliant to treat a bool as an unsigned integer type with values 0
  25. // and 1.
  26. using bit_t = bool;
  27. // Counts of the number of bits in a value are of this type, which must
  28. // be large enough to store the _value_ VALUE_BITS
  29. using nbits_t = uint8_t;
  30. // Convert a number of bits to the number of bytes required to store (or
  31. // more to the point, send) them.
  32. #define BITBYTES(nbits) (((nbits)+7)>>3)
  33. // A mask of this many bits; the test is to prevent 1<<nbits from
  34. // overflowing if nbits == VALUE_BITS
  35. #define MASKBITS(nbits) (((nbits) < VALUE_BITS) ? (value_t(1)<<(nbits))-1 : ~0)
  36. // The type of a register holding an additive share of a value
  37. struct RegAS {
  38. value_t ashare;
  39. RegAS() : ashare(0) {}
  40. inline value_t share() const { return ashare; }
  41. inline void set(value_t s) { ashare = s; }
  42. // Set each side's share to a random value nbits bits long
  43. inline void randomize(size_t nbits = VALUE_BITS) {
  44. value_t mask = MASKBITS(nbits);
  45. arc4random_buf(&ashare, sizeof(ashare));
  46. ashare &= mask;
  47. }
  48. inline RegAS &operator+=(const RegAS &rhs) {
  49. this->ashare += rhs.ashare;
  50. return *this;
  51. }
  52. inline RegAS operator+(const RegAS &rhs) const {
  53. RegAS res = *this;
  54. res += rhs;
  55. return res;
  56. }
  57. inline RegAS &operator-=(const RegAS &rhs) {
  58. this->ashare -= rhs.ashare;
  59. return *this;
  60. }
  61. inline RegAS operator-(const RegAS &rhs) const {
  62. RegAS res = *this;
  63. res -= rhs;
  64. return res;
  65. }
  66. inline RegAS operator-() const {
  67. RegAS res = *this;
  68. res.ashare = -res.ashare;
  69. return res;
  70. }
  71. inline RegAS &operator*=(value_t rhs) {
  72. this->ashare *= rhs;
  73. return *this;
  74. }
  75. inline RegAS operator*(value_t rhs) const {
  76. RegAS res = *this;
  77. res *= rhs;
  78. return res;
  79. }
  80. inline RegAS &operator&=(value_t mask) {
  81. this->ashare &= mask;
  82. return *this;
  83. }
  84. inline RegAS operator&(value_t mask) const {
  85. RegAS res = *this;
  86. res &= mask;
  87. return res;
  88. }
  89. // Multiply by the local share of the argument, not multiplcation of
  90. // two shared values (two versions)
  91. inline RegAS &mulshareeq(const RegAS &rhs) {
  92. *this *= rhs.ashare;
  93. return *this;
  94. }
  95. inline RegAS mulshare(const RegAS &rhs) const {
  96. RegAS res = *this;
  97. res *= rhs.ashare;
  98. return res;
  99. }
  100. inline void dump() const {
  101. printf("%016lx", ashare);
  102. }
  103. };
  104. inline value_t combine(const RegAS &A, const RegAS &B,
  105. nbits_t nbits = VALUE_BITS) {
  106. value_t mask = ~0;
  107. if (nbits < VALUE_BITS) {
  108. mask = (value_t(1)<<nbits)-1;
  109. }
  110. return (A.ashare + B.ashare) & mask;
  111. }
  112. // The type of a register holding a bit share
  113. struct RegBS {
  114. bit_t bshare;
  115. RegBS() : bshare(0) {}
  116. inline bit_t share() const { return bshare; }
  117. inline void set(bit_t s) { bshare = s; }
  118. // Set each side's share to a random bit
  119. inline void randomize() {
  120. unsigned char randb;
  121. arc4random_buf(&randb, sizeof(randb));
  122. bshare = randb & 1;
  123. }
  124. inline RegBS &operator^=(const RegBS &rhs) {
  125. this->bshare ^= rhs.bshare;
  126. return *this;
  127. }
  128. inline RegBS operator^(const RegBS &rhs) const {
  129. RegBS res = *this;
  130. res ^= rhs;
  131. return res;
  132. }
  133. inline RegBS &operator^=(const bit_t &rhs) {
  134. this->bshare ^= rhs;
  135. return *this;
  136. }
  137. inline RegBS operator^(const bit_t &rhs) const {
  138. RegBS res = *this;
  139. res ^= rhs;
  140. return res;
  141. }
  142. };
  143. // The type of a register holding an XOR share of a value
  144. struct RegXS {
  145. value_t xshare;
  146. RegXS() : xshare(0) {}
  147. RegXS(const RegBS &b) { xshare = b.bshare ? ~0 : 0; }
  148. inline value_t share() const { return xshare; }
  149. inline void set(value_t s) { xshare = s; }
  150. // Set each side's share to a random value nbits bits long
  151. inline void randomize(size_t nbits = VALUE_BITS) {
  152. value_t mask = MASKBITS(nbits);
  153. arc4random_buf(&xshare, sizeof(xshare));
  154. xshare &= mask;
  155. }
  156. // For RegXS, + and * should be interpreted bitwise; that is, + is
  157. // really XOR and * is really AND. - is also XOR (the same as +).
  158. // We also include actual XOR operators for convenience
  159. inline RegXS &operator+=(const RegXS &rhs) {
  160. this->xshare ^= rhs.xshare;
  161. return *this;
  162. }
  163. inline RegXS operator+(const RegXS &rhs) const {
  164. RegXS res = *this;
  165. res += rhs;
  166. return res;
  167. }
  168. inline RegXS &operator-=(const RegXS &rhs) {
  169. this->xshare ^= rhs.xshare;
  170. return *this;
  171. }
  172. inline RegXS operator-(const RegXS &rhs) const {
  173. RegXS res = *this;
  174. res -= rhs;
  175. return res;
  176. }
  177. inline RegXS operator-() const {
  178. RegXS res = *this;
  179. return res;
  180. }
  181. inline RegXS &operator*=(value_t rhs) {
  182. this->xshare &= rhs;
  183. return *this;
  184. }
  185. inline RegXS operator*(value_t rhs) const {
  186. RegXS res = *this;
  187. res *= rhs;
  188. return res;
  189. }
  190. inline RegXS &operator^=(const RegXS &rhs) {
  191. this->xshare ^= rhs.xshare;
  192. return *this;
  193. }
  194. inline RegXS operator^(const RegXS &rhs) const {
  195. RegXS res = *this;
  196. res ^= rhs;
  197. return res;
  198. }
  199. inline RegXS &operator&=(value_t mask) {
  200. this->xshare &= mask;
  201. return *this;
  202. }
  203. inline RegXS operator&(value_t mask) const {
  204. RegXS res = *this;
  205. res &= mask;
  206. return res;
  207. }
  208. // Bit shifting and bit extraction
  209. inline RegXS &operator<<=(nbits_t shift) {
  210. this->xshare <<= shift;
  211. return *this;
  212. }
  213. inline RegXS operator<<(nbits_t shift) const {
  214. RegXS res = *this;
  215. res <<= shift;
  216. return res;
  217. }
  218. inline RegXS &operator>>=(nbits_t shift) {
  219. this->xshare >>= shift;
  220. return *this;
  221. }
  222. inline RegXS operator>>(nbits_t shift) const {
  223. RegXS res = *this;
  224. res >>= shift;
  225. return res;
  226. }
  227. inline RegBS bitat(nbits_t pos) const {
  228. RegBS bs;
  229. bs.set(!!(this->xshare & (value_t(1)<<pos)));
  230. return bs;
  231. }
  232. // Multiply by the local share of the argument, not multiplcation of
  233. // two shared values (two versions)
  234. inline RegXS &mulshareeq(const RegXS &rhs) {
  235. *this *= rhs.xshare;
  236. return *this;
  237. }
  238. inline RegXS mulshare(const RegXS &rhs) const {
  239. RegXS res = *this;
  240. res *= rhs.xshare;
  241. return res;
  242. }
  243. inline void dump() const {
  244. printf("%016lx", xshare);
  245. }
  246. // Extract a bit share of bit bitnum of the XOR-shared register
  247. inline RegBS bit(nbits_t bitnum) const {
  248. RegBS bs;
  249. bs.bshare = !!(xshare & (value_t(1)<<bitnum));
  250. return bs;
  251. }
  252. };
  253. inline value_t combine(const RegXS &A, const RegXS &B,
  254. nbits_t nbits = VALUE_BITS) {
  255. value_t mask = ~0;
  256. if (nbits < VALUE_BITS) {
  257. mask = (value_t(1)<<nbits)-1;
  258. }
  259. return (A.xshare ^ B.xshare) & mask;
  260. }
  261. // Enable templates to specialize on just the basic types RegAS and
  262. // RegXS. Technique from
  263. // https://stackoverflow.com/questions/2430039/one-template-specialization-for-multiple-classes
  264. template <bool B> struct prac_template_bool_type {};
  265. using prac_template_true = prac_template_bool_type<true>;
  266. using prac_template_false = prac_template_bool_type<false>;
  267. template <typename T>
  268. struct prac_basic_Reg_S : prac_template_false
  269. {
  270. static const bool value = false;
  271. };
  272. template<>
  273. struct prac_basic_Reg_S<RegAS>: prac_template_true
  274. {
  275. static const bool value = true;
  276. };
  277. template<>
  278. struct prac_basic_Reg_S<RegXS>: prac_template_true
  279. {
  280. static const bool value = true;
  281. };
  282. // Some useful operations on tuples, vectors, and arrays of the above
  283. // types
  284. template <typename T>
  285. std::tuple<T,T> operator+=(std::tuple<T,T> &A,
  286. const std::tuple<T,T> &B)
  287. {
  288. std::get<0>(A) += std::get<0>(B);
  289. std::get<1>(A) += std::get<1>(B);
  290. return A;
  291. }
  292. template <typename T>
  293. std::tuple<T,T> operator+=(const std::tuple<T&,T&> &A,
  294. const std::tuple<T,T> &B)
  295. {
  296. std::get<0>(A) += std::get<0>(B);
  297. std::get<1>(A) += std::get<1>(B);
  298. return A;
  299. }
  300. template <typename T>
  301. std::tuple<T,T> operator+(const std::tuple<T,T> &A,
  302. const std::tuple<T,T> &B)
  303. {
  304. auto res = A;
  305. res += B;
  306. return res;
  307. }
  308. template <typename T>
  309. std::tuple<T,T> operator-=(const std::tuple<T&,T&> &A,
  310. const std::tuple<T,T> &B)
  311. {
  312. std::get<0>(A) -= std::get<0>(B);
  313. std::get<1>(A) -= std::get<1>(B);
  314. return A;
  315. }
  316. template <typename T>
  317. std::tuple<T,T> operator-=(std::tuple<T,T> &A,
  318. const std::tuple<T,T> &B)
  319. {
  320. std::get<0>(A) -= std::get<0>(B);
  321. std::get<1>(A) -= std::get<1>(B);
  322. return A;
  323. }
  324. template <typename T>
  325. std::tuple<T,T> operator-(const std::tuple<T,T> &A,
  326. const std::tuple<T,T> &B)
  327. {
  328. auto res = A;
  329. res -= B;
  330. return res;
  331. }
  332. template <typename T>
  333. std::tuple<T,T> operator*=(const std::tuple<T&,T&> &A,
  334. const std::tuple<value_t,value_t> &B)
  335. {
  336. std::get<0>(A) *= std::get<0>(B);
  337. std::get<1>(A) *= std::get<1>(B);
  338. return A;
  339. }
  340. template <typename T>
  341. std::tuple<T,T> operator*=(std::tuple<T,T> &A,
  342. const std::tuple<value_t,value_t> &B)
  343. {
  344. std::get<0>(A) *= std::get<0>(B);
  345. std::get<1>(A) *= std::get<1>(B);
  346. return A;
  347. }
  348. template <typename T>
  349. std::tuple<T,T> operator*(const std::tuple<T,T> &A,
  350. const std::tuple<value_t,value_t> &B)
  351. {
  352. auto res = A;
  353. res *= B;
  354. return res;
  355. }
  356. template <typename T>
  357. inline std::tuple<value_t,value_t> combine(
  358. const std::tuple<T,T> &A, const std::tuple<T,T> &B,
  359. nbits_t nbits = VALUE_BITS) {
  360. return std::make_tuple(
  361. combine(std::get<0>(A), std::get<0>(B), nbits),
  362. combine(std::get<1>(A), std::get<1>(B), nbits));
  363. }
  364. template <typename T>
  365. std::tuple<T,T,T> operator+=(const std::tuple<T&,T&,T&> &A,
  366. const std::tuple<T,T,T> &B)
  367. {
  368. std::get<0>(A) += std::get<0>(B);
  369. std::get<1>(A) += std::get<1>(B);
  370. std::get<2>(A) += std::get<2>(B);
  371. return A;
  372. }
  373. template <typename T>
  374. std::tuple<T,T,T> operator+=(std::tuple<T,T,T> &A,
  375. const std::tuple<T,T,T> &B)
  376. {
  377. std::get<0>(A) += std::get<0>(B);
  378. std::get<1>(A) += std::get<1>(B);
  379. std::get<2>(A) += std::get<2>(B);
  380. return A;
  381. }
  382. template <typename T>
  383. std::tuple<T,T,T> operator+(const std::tuple<T,T,T> &A,
  384. const std::tuple<T,T,T> &B)
  385. {
  386. auto res = A;
  387. res += B;
  388. return res;
  389. }
  390. template <typename T>
  391. std::tuple<T,T,T> operator-=(const std::tuple<T&,T&,T&> &A,
  392. const std::tuple<T,T,T> &B)
  393. {
  394. std::get<0>(A) -= std::get<0>(B);
  395. std::get<1>(A) -= std::get<1>(B);
  396. std::get<2>(A) -= std::get<2>(B);
  397. return A;
  398. }
  399. template <typename T>
  400. std::tuple<T,T,T> operator-=(std::tuple<T,T,T> &A,
  401. const std::tuple<T,T,T> &B)
  402. {
  403. std::get<0>(A) -= std::get<0>(B);
  404. std::get<1>(A) -= std::get<1>(B);
  405. std::get<2>(A) -= std::get<2>(B);
  406. return A;
  407. }
  408. template <typename T>
  409. std::tuple<T,T,T> operator-(const std::tuple<T,T,T> &A,
  410. const std::tuple<T,T,T> &B)
  411. {
  412. auto res = A;
  413. res -= B;
  414. return res;
  415. }
  416. template <typename T>
  417. std::tuple<T,T,T> operator*=(const std::tuple<T&,T&,T&> &A,
  418. const std::tuple<value_t,value_t,value_t> &B)
  419. {
  420. std::get<0>(A) *= std::get<0>(B);
  421. std::get<1>(A) *= std::get<1>(B);
  422. std::get<2>(A) *= std::get<2>(B);
  423. return A;
  424. }
  425. template <typename T>
  426. std::tuple<T,T,T> operator*=(std::tuple<T,T,T> &A,
  427. const std::tuple<value_t,value_t,value_t> &B)
  428. {
  429. std::get<0>(A) *= std::get<0>(B);
  430. std::get<1>(A) *= std::get<1>(B);
  431. std::get<2>(A) *= std::get<2>(B);
  432. return A;
  433. }
  434. template <typename T>
  435. std::tuple<T,T,T> operator*(const std::tuple<T,T,T> &A,
  436. const std::tuple<value_t,value_t,value_t> &B)
  437. {
  438. auto res = A;
  439. res *= B;
  440. return res;
  441. }
  442. inline std::vector<RegAS> operator-(const std::vector<RegAS> &A)
  443. {
  444. std::vector<RegAS> res;
  445. for (const auto &v : A) {
  446. res.push_back(-v);
  447. }
  448. return res;
  449. }
  450. inline std::vector<RegXS> operator-(const std::vector<RegXS> &A)
  451. {
  452. return A;
  453. }
  454. inline std::vector<RegBS> operator-(const std::vector<RegBS> &A)
  455. {
  456. return A;
  457. }
  458. template <size_t N>
  459. inline std::vector<RegAS> operator-(const std::array<RegAS,N> &A)
  460. {
  461. std::vector<RegAS> res;
  462. for (const auto &v : A) {
  463. res.push_back(-v);
  464. }
  465. return res;
  466. }
  467. template <size_t N>
  468. inline std::array<RegXS,N> operator-(const std::array<RegXS,N> &A)
  469. {
  470. return A;
  471. }
  472. template <size_t N>
  473. inline std::array<RegBS,N> operator-(const std::array<RegBS,N> &A)
  474. {
  475. return A;
  476. }
  477. template <typename T>
  478. inline std::tuple<value_t,value_t,value_t> combine(
  479. const std::tuple<T,T,T> &A, const std::tuple<T,T,T> &B,
  480. nbits_t nbits = VALUE_BITS) {
  481. return std::make_tuple(
  482. combine(std::get<0>(A), std::get<0>(B), nbits),
  483. combine(std::get<1>(A), std::get<1>(B), nbits),
  484. combine(std::get<2>(A), std::get<2>(B), nbits));
  485. }
  486. // The _maximum_ number of bits in an MPC address; the actual size of
  487. // the memory will typically be set at runtime, but it cannot exceed
  488. // this value. It is more efficient (in terms of communication) in some
  489. // places for this value to be at most 32.
  490. #ifndef ADDRESS_MAX_BITS
  491. #define ADDRESS_MAX_BITS 32
  492. #endif
  493. // Addresses of MPC secret-shared memory are of this type
  494. #if ADDRESS_MAX_BITS <= 32
  495. using address_t = uint32_t;
  496. #elif ADDRESS_MAX_BITS <= 64
  497. using address_t = uint64_t;
  498. #else
  499. #error "Unsupported value of ADDRESS_MAX_BITS"
  500. #endif
  501. #if ADDRESS_MAX_BITS > VALUE_BITS
  502. #error "VALUE_BITS must be at least as large as ADDRESS_MAX_BITS"
  503. #endif
  504. // A multiplication triple is a triple (X0,Y0,Z0) held by P0 (and
  505. // correspondingly (X1,Y1,Z1) held by P1), with all values random,
  506. // but subject to the relation that X0*Y1 + Y0*X1 = Z0+Z1
  507. using MultTriple = std::tuple<value_t, value_t, value_t>;
  508. // The *Name structs are a way to get strings representing the names of
  509. // the types as would be given to preprocessing to create them in
  510. // advance.
  511. struct MultTripleName { static constexpr const char *name = "m"; };
  512. // A half-triple is (X0,Z0) held by P0 (and correspondingly (Y1,Z1) held
  513. // by P1), with all values random, but subject to the relation that
  514. // X0*Y1 = Z0+Z1
  515. using HalfTriple = std::tuple<value_t, value_t>;
  516. struct HalfTripleName { static constexpr const char *name = "h"; };
  517. // An AND triple is a triple (X0,Y0,Z0) held by P0 (and correspondingly
  518. // (X1,Y1,Z1) held by P1), with all values random, but subject to the
  519. // relation that X0&Y1 ^ Y0&X1 = Z0^Z1
  520. using AndTriple = std::tuple<value_t, value_t, value_t>;
  521. struct AndTripleName { static constexpr const char *name = "a"; };
  522. // The type of nodes in a DPF. This must be at least as many bits as
  523. // the security parameter, and at least twice as many bits as value_t.
  524. using DPFnode = __m128i;
  525. // A Select triple for type V (V is DPFnode, value_t, or bit_t) is a
  526. // triple of (X0,Y0,Z0) where X0 is a bit and Y0 and Z0 are Vs held by
  527. // P0 (and correspondingly (X1,Y1,Z1) held by P1), with all values
  528. // random, but subject to the relation that (X0*Y1) ^ (Y0*X1) = Z0^Z1.
  529. // This is a struct instead of a tuple for alignment reasons.
  530. template <typename V>
  531. struct SelectTriple {
  532. bit_t X;
  533. V Y, Z;
  534. };
  535. // Of the three options for V, we only ever store V = value_t
  536. struct ValSelectTripleName { static constexpr const char *name = "s"; };
  537. // These are defined in rdpf.hpp, but declared here to avoid cyclic
  538. // header dependencies.
  539. template <nbits_t WIDTH> struct RDPFPair;
  540. struct RDPFPairName { static constexpr const char *name = "r"; };
  541. template <nbits_t WIDTH> struct RDPFTriple;
  542. struct RDPFTripleName { static constexpr const char *name = "r"; };
  543. struct CDPF;
  544. struct CDPFName { static constexpr const char *name = "c"; };
  545. // We want the I/O (using << and >>) for many classes
  546. // to just be a common thing: write out the bytes
  547. // straight from memory
  548. #define DEFAULT_IO(CLASSNAME) \
  549. template <typename T> \
  550. T& operator>>(T& is, CLASSNAME &x) \
  551. { \
  552. is.read((char *)&x, sizeof(x)); \
  553. return is; \
  554. } \
  555. \
  556. template <typename T> \
  557. T& operator<<(T& os, const CLASSNAME &x) \
  558. { \
  559. os.write((const char *)&x, sizeof(x)); \
  560. return os; \
  561. }
  562. // Default I/O for various types
  563. DEFAULT_IO(DPFnode)
  564. DEFAULT_IO(RegBS)
  565. DEFAULT_IO(RegAS)
  566. DEFAULT_IO(RegXS)
  567. DEFAULT_IO(MultTriple)
  568. DEFAULT_IO(HalfTriple)
  569. // We don't need one for AndTriple because it's exactly the same type as
  570. // MultTriple
  571. // I/O for SelectTriples
  572. template <typename T, typename V>
  573. T& operator>>(T& is, SelectTriple<V> &x)
  574. {
  575. is.read((char *)&x.X, sizeof(x.X));
  576. is.read((char *)&x.Y, sizeof(x.Y));
  577. is.read((char *)&x.Z, sizeof(x.Z));
  578. return is;
  579. }
  580. template <typename T, typename V>
  581. T& operator<<(T& os, const SelectTriple<V> &x)
  582. {
  583. os.write((const char *)&x.X, sizeof(x.X));
  584. os.write((const char *)&x.Y, sizeof(x.Y));
  585. os.write((const char *)&x.Z, sizeof(x.Z));
  586. return os;
  587. }
  588. // And for pairs and triples
  589. #define DEFAULT_TUPLE_IO(CLASSNAME) \
  590. template <typename T> \
  591. T& operator>>(T& is, std::tuple<CLASSNAME, CLASSNAME> &x) \
  592. { \
  593. is >> std::get<0>(x) >> std::get<1>(x); \
  594. return is; \
  595. } \
  596. \
  597. template <typename T> \
  598. T& operator<<(T& os, const std::tuple<CLASSNAME, CLASSNAME> &x) \
  599. { \
  600. os << std::get<0>(x) << std::get<1>(x); \
  601. return os; \
  602. } \
  603. \
  604. template <typename T> \
  605. T& operator>>(T& is, std::tuple<CLASSNAME, CLASSNAME, CLASSNAME> &x) \
  606. { \
  607. is >> std::get<0>(x) >> std::get<1>(x) >> std::get<2>(x); \
  608. return is; \
  609. } \
  610. \
  611. template <typename T> \
  612. T& operator<<(T& os, const std::tuple<CLASSNAME, CLASSNAME, CLASSNAME> &x) \
  613. { \
  614. os << std::get<0>(x) << std::get<1>(x) << std::get<2>(x); \
  615. return os; \
  616. }
  617. DEFAULT_TUPLE_IO(RegAS)
  618. DEFAULT_TUPLE_IO(RegXS)
  619. enum ProcessingMode {
  620. MODE_ONLINE, // Online mode, after preprocessing has been done
  621. MODE_PREPROCESSING, // Preprocessing mode
  622. MODE_ONLINEONLY // Online-only mode, where all computations are
  623. }; // done online
  624. #endif