2 * Eddie Kohler, Yandong Mao, Robert Morris
3 * Copyright (c) 2012-2014 President and Fellows of Harvard College
4 * Copyright (c) 2012-2014 Massachusetts Institute of Technology
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, subject to the conditions
9 * listed in the Masstree LICENSE file. These conditions include: you must
10 * preserve this copyright notice, and you cannot mention the copyright
11 * holders in advertising related to the Software without their permission.
12 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13 * notice is a summary of the Masstree LICENSE file; the license in that file
20 class identity_kpermuter {
23 identity_kpermuter(int size)
30 int operator[](int i) const {
33 bool operator==(const identity_kpermuter&) const {
36 bool operator!=(const identity_kpermuter&) const {
41 template <int C> struct sized_kpermuter_info {};
42 template <> struct sized_kpermuter_info<0> {
43 typedef uint16_t storage_type;
44 typedef unsigned value_type;
45 enum { initial_value = 0x0120U, full_value = 0x2100U };
47 template <> struct sized_kpermuter_info<1> {
48 typedef uint32_t storage_type;
49 typedef unsigned value_type;
50 enum { initial_value = 0x01234560U, full_value = 0x65432100U };
52 template <> struct sized_kpermuter_info<2> {
53 typedef uint64_t storage_type;
54 typedef uint64_t value_type;
55 enum { initial_value = (uint64_t) 0x0123456789ABCDE0ULL,
56 full_value = (uint64_t) 0xEDCBA98765432100ULL };
59 template <int width> class kpermuter {
61 typedef sized_kpermuter_info<(width > 3) + (width > 7) + (width > 15)> info;
62 typedef typename info::storage_type storage_type;
63 typedef typename info::value_type value_type;
64 enum { max_width = (int) (sizeof(storage_type) * 2 - 1) };
65 enum { size_bits = 4 };
67 /** @brief Construct an uninitialized permuter. */
70 /** @brief Construct a permuter with value @a x. */
71 kpermuter(value_type x)
75 /** @brief Return an empty permuter with size 0.
77 Elements will be allocated in order 0, 1, ..., @a width - 1. */
78 static inline value_type make_empty() {
79 value_type p = (value_type) info::initial_value >> ((max_width - width) << 2);
80 return p & ~(value_type) 15;
82 /** @brief Return a permuter with size @a n.
84 The returned permutation has size() @a n. For 0 <= i < @a n,
85 (*this)[i] == i. Elements n through @a width - 1 are free, and will be
86 allocated in that order. */
87 static inline value_type make_sorted(int n) {
88 value_type mask = (n == width ? (value_type) 0 : (value_type) 16 << (n << 2)) - 1;
89 return (make_empty() << (n << 2))
90 | ((value_type) info::full_value & mask)
94 /** @brief Return the permuter's size. */
98 /** @brief Return the permuter's element @a i.
99 @pre 0 <= i < width */
100 int operator[](int i) const {
101 return (x_ >> ((i << 2) + 4)) & 15;
104 return (*this)[width - 1];
106 value_type value() const {
109 value_type value_from(int i) const {
110 return x_ >> ((i + 1) << 2);
113 void set_size(int n) {
114 x_ = (x_ & ~(value_type) 15) | n;
116 /** @brief Allocate a new element and insert it at position @a i.
117 @pre 0 <= @a i < @a width
118 @pre size() < @a width
119 @return The newly allocated element.
121 Consider the following code:
123 kpermuter<...> p = ..., q = p;
124 int x = q.insert_from_back(i);
127 The modified permuter, q, has the following properties.
129 <li>q.size() == p.size() + 1</li>
130 <li>Given j with 0 <= j < i, q[j] == p[j] && q[j] != x</li>
131 <li>Given j with j == i, q[j] == x</li>
132 <li>Given j with i < j < q.size(), q[j] == p[j-1] && q[j] != x</li>
134 int insert_from_back(int i) {
136 // increment size, leave lower slots unchanged
137 x_ = ((x_ + 1) & (((value_type) 16 << (i << 2)) - 1))
139 | ((value_type) value << ((i << 2) + 4))
140 // shift up unchanged higher entries & empty slots
141 | ((x_ << 4) & ~(((value_type) 256 << (i << 2)) - 1));
144 /** @brief Insert an unallocated element from position @a si at position @a di.
145 @pre 0 <= @a di < @a width
146 @pre size() < @a width
148 @return The newly allocated element. */
149 void insert_selected(int di, int si) {
151 int value = (*this)[si];
152 value_type mask = ((value_type) 256 << (si << 2)) - 1;
153 // increment size, leave lower slots unchanged
154 x_ = ((x_ + 1) & (((value_type) 16 << (di << 2)) - 1))
156 | ((value_type) value << ((di << 2) + 4))
157 // shift up unchanged higher entries & empty slots
158 | ((x_ << 4) & mask & ~(((value_type) 256 << (di << 2)) - 1))
159 // leave uppermost slots alone
162 /** @brief Remove the element at position @a i.
163 @pre 0 <= @a i < @a size()
164 @pre size() < @a width
166 Consider the following code:
168 kpermuter<...> p = ..., q = p;
172 The modified permuter, q, has the following properties.
174 <li>q.size() == p.size() - 1</li>
175 <li>Given j with 0 <= j < i, q[j] == p[j]</li>
176 <li>Given j with i <= j < q.size(), q[j] == p[j+1]</li>
177 <li>q[q.size()] == p[i]</li>
181 if (int(x_ & 15) == i + 1)
184 int rot_amount = ((x_ & 15) - i - 1) << 2;
185 value_type rot_mask =
186 (((value_type) 16 << rot_amount) - 1) << ((i + 1) << 2);
187 // decrement size, leave lower slots unchanged
188 x_ = ((x_ - 1) & ~rot_mask)
189 // shift higher entries down
190 | (((x_ & rot_mask) >> 4) & rot_mask)
192 | (((x_ & rot_mask) << rot_amount) & rot_mask);
195 /** @brief Remove the element at position @a i to the back.
196 @pre 0 <= @a i < @a size()
197 @pre size() < @a width
199 Consider the following code:
201 kpermuter<...> p = ..., q = p;
205 The modified permuter, q, has the following properties.
207 <li>q.size() == p.size() - 1</li>
208 <li>Given j with 0 <= j < i, q[j] == p[j]</li>
209 <li>Given j with i <= j < @a width - 1, q[j] == p[j+1]</li>
210 <li>q.back() == p[i]</li>
212 void remove_to_back(int i) {
213 value_type mask = ~(((value_type) 16 << (i << 2)) - 1);
214 // clear unused slots
215 value_type x = x_ & (((value_type) 16 << (width << 2)) - 1);
216 // decrement size, leave lower slots unchanged
217 x_ = ((x - 1) & ~mask)
218 // shift higher entries down
220 // shift removed element up
221 | ((x & mask) << ((width - i - 1) << 2));
223 /** @brief Rotate the permuter's elements between @a i and size().
224 @pre 0 <= @a i <= @a j <= size()
226 Consider the following code:
228 kpermuter<...> p = ..., q = p;
232 The modified permuter, q, has the following properties.
234 <li>q.size() == p.size()</li>
235 <li>Given k with 0 <= k < i, q[k] == p[k]</li>
236 <li>Given k with i <= k < q.size(), q[k] == p[i + (k - i + j - i) mod (size() - i)]</li>
238 void rotate(int i, int j) {
239 value_type mask = (i == width ? (value_type) 0 : (value_type) 16 << (i << 2)) - 1;
240 // clear unused slots
241 value_type x = x_ & (((value_type) 16 << (width << 2)) - 1);
243 | ((x >> ((j - i) << 2)) & ~mask)
244 | ((x & ~mask) << ((width - j) << 2));
246 /** @brief Exchange the elements at positions @a i and @a j. */
247 void exchange(int i, int j) {
248 value_type diff = ((x_ >> (i << 2)) ^ (x_ >> (j << 2))) & 240;
249 x_ ^= (diff << (i << 2)) | (diff << (j << 2));
251 /** @brief Exchange positions of values @a x and @a y. */
252 void exchange_values(int x, int y) {
253 value_type diff = 0, p = x_;
254 for (int i = 0; i < width; ++i, diff <<= 4, p <<= 4) {
255 int v = (p >> (width << 2)) & 15;
256 diff ^= -((v == x) | (v == y)) & (x ^ y);
261 lcdf::String unparse() const;
263 bool operator==(const kpermuter<width>& x) const {
266 bool operator!=(const kpermuter<width>& x) const {
267 return !(*this == x);
270 static inline int size(value_type p) {
278 lcdf::String kpermuter<width>::unparse() const
280 char buf[max_width + 3], *s = buf;
285 for (int i = 0; true; ++i) {
291 *s++ = '0' + (p & 15);
293 *s++ = 'a' + (p & 15) - 10;
294 seen |= 1 << (p & 15);
297 if (seen != (1 << width) - 1) {
301 return lcdf::String(buf, s);
305 template <typename T> struct has_permuter_type {
306 template <typename C> static char test(typename C::permuter_type *);
307 template <typename> static int test(...);
308 static constexpr bool value = sizeof(test<T>(0)) == 1;
311 template <typename T, bool HP = has_permuter_type<T>::value> struct key_permuter {};
312 template <typename T> struct key_permuter<T, true> {
313 typedef typename T::permuter_type type;
314 static type permutation(const T& n) {
315 return n.permutation();
318 template <typename T> struct key_permuter<T, false> {
319 typedef identity_kpermuter type;
320 static type permutation(const T& n) {
321 return identity_kpermuter(n.size());