8 #ifndef Sawyer_BitVectorSupport_H
9 #define Sawyer_BitVectorSupport_H
12 #include <boost/cstdint.hpp>
13 #include <boost/foreach.hpp>
14 #include <boost/lexical_cast.hpp>
16 #include <Sawyer/Assert.h>
17 #include <Sawyer/Interval.h>
18 #include <Sawyer/Optional.h>
19 #include <Sawyer/Sawyer.h>
27 namespace BitVectorSupport {
31 template<
class T>
struct RemoveConst<const T> {
typedef T Base; };
42 enum { value = 8 *
sizeof(Word) };
72 Word
bitMask(
size_t offset,
size_t nbits) {
75 return mask << offset;
83 template<
class Processor,
class Word>
84 bool processWord(Processor &processor,
const Word &word,
size_t shift,
size_t nbits) {
87 const Word tmp = word >> shift;
88 return processor(tmp, nbits);
91 template<
class Processor,
class Word>
92 bool processWord(Processor &processor, Word &word,
size_t shift,
size_t nbits) {
94 Word tmp = word >> shift;
95 bool retval = processor(tmp, nbits);
96 word &= ~bitMask<Word>(shift, nbits);
97 word |= (tmp & bitMask<Word>(0, nbits)) << shift;
101 template<
class Processor,
class Word>
102 bool processWord(Processor &processor,
const Word &src, Word &dst,
size_t shift,
size_t nbits) {
105 const Word tmpSrc = src >> shift;
106 Word tmpDst = dst >> shift;
107 bool retval = processor(tmpSrc, tmpDst, nbits);
108 dst &= ~bitMask<Word>(shift, nbits);
109 dst |= (tmpDst & bitMask<Word>(0, nbits)) << shift;
112 template<
class Processor,
class Word>
113 bool processWord(Processor &processor, Word &w1, Word &w2,
size_t shift,
size_t nbits) {
116 Word tmp1 = w1 >> shift;
117 Word tmp2 = w2 >> shift;
118 bool retval = processor(tmp1, tmp2, nbits);
119 Word mask = bitMask<Word>(shift, nbits);
121 w1 |= (tmp1 << shift) & mask;
123 w2 |= (tmp2 << shift) & mask;
126 template<
class Processor,
class Word>
127 bool processWord(Processor &processor,
const Word &w1,
const Word &w2,
size_t shift,
size_t nbits) {
130 Word tmp1 = w1 >> shift;
131 Word tmp2 = w2 >> shift;
132 return processor(tmp1, tmp2, nbits);
138 void nonoverlappingCopy(
const Word *src,
const BitRange &srcRange, Word *dst,
const BitRange &dstRange) {
139 ASSERT_require(srcRange.size()==dstRange.size());
140 ASSERT_require(src != dst);
142 size_t dstFirstIdx = wordIndex<Word>(dstRange.least());
143 size_t dstLastIdx = wordIndex<Word>(dstRange.greatest());
144 size_t srcFirstIdx = wordIndex<Word>(srcRange.least());
145 size_t srcLastIdx = wordIndex<Word>(srcRange.greatest());
147 size_t srcOffset = srcFirstIdx - dstFirstIdx;
149 size_t srcBitIdx = bitIndex<Word>(srcRange.least());
150 size_t dstBitIdx = bitIndex<Word>(dstRange.least());
152 if (srcBitIdx < dstBitIdx) {
154 const size_t leftShiftAmount = dstBitIdx - srcBitIdx;
155 const size_t rightShiftAmount = bitsPerWord<Word>::value - leftShiftAmount;
157 for (
size_t i=dstFirstIdx; i<=dstLastIdx; ++i) {
158 const Word tmp = (i+srcOffset > srcFirstIdx ? (src[i+srcOffset-1] >> rightShiftAmount) : Word(0)) |
159 (i+srcOffset > srcLastIdx ? Word(0) : (src[i+srcOffset] << leftShiftAmount));
160 Word mask = bitMask<Word>(0, bitsPerWord<Word>::value);
162 mask &= ~bitMask<Word>(0, bitIndex<Word>(dstRange.least()));
164 mask &= bitMask<Word>(0, bitIndex<Word>(dstRange.greatest())+1);
166 dst[i] |= tmp & mask;
168 }
else if (srcBitIdx > dstBitIdx) {
170 const size_t rightShiftAmount = srcBitIdx - dstBitIdx;
171 const size_t leftShiftAmount = bitsPerWord<Word>::value - rightShiftAmount;
173 for (
size_t i=dstFirstIdx; i<=dstLastIdx; ++i) {
174 const Word tmp = (src[i+srcOffset] >> rightShiftAmount) |
175 (i+srcOffset+1 <= srcLastIdx ? (src[i+srcOffset+1] << leftShiftAmount) : Word(0));
176 Word mask = bitMask<Word>(0, bitsPerWord<Word>::value);
178 mask &= ~bitMask<Word>(0, bitIndex<Word>(dstRange.least()));
180 mask &= bitMask<Word>(0, bitIndex<Word>(dstRange.greatest())+1);
182 dst[i] |= tmp & mask;
186 for (
size_t i=dstFirstIdx; i<=dstLastIdx; ++i) {
187 const Word tmp = src[i+srcOffset];
188 Word
mask = bitMask<Word>(0, bitsPerWord<Word>::value);
190 mask &= ~bitMask<Word>(0, bitIndex<Word>(dstRange.least()));
192 mask &= bitMask<Word>(0, bitIndex<Word>(dstRange.greatest())+1);
194 dst[i] |= tmp &
mask;
199 template<
class Src,
class Dst>
200 void conditionalCopy(
const Src *src,
const BitRange &srcRange, Dst *dst,
const BitRange &dstRange) {
201 nonoverlappingCopy(src, srcRange, dst, dstRange);
203 template<
class Src,
class Dst>
204 void conditionalCopy(
const Src *,
const BitRange &,
const Dst *,
const BitRange &) {
213 template<
class Processor,
class Word>
217 size_t nRemaining = range.
size();
218 size_t offsetInWord = bitIndex<Word>(range.
least());
220 for (
size_t wordIdx = wordIndex<Word>(range.
least()); !done && nRemaining > 0; ++wordIdx) {
222 ASSERT_require(nbits > 0);
223 done =
processWord(processor, words[wordIdx], offsetInWord, nbits);
230 template<
class Processor,
class Word>
234 size_t nRemaining = range.
size();
235 size_t offsetInWord = bitIndex<Word>(range.
least());
237 size_t firstWordIdx = wordIndex<Word>(range.
least());
238 size_t lastWordIdx = wordIndex<Word>(range.
greatest());
239 for (
size_t wordIdx=lastWordIdx; !done && nRemaining > 0; --wordIdx) {
241 if (wordIdx == firstWordIdx) {
244 }
else if (wordIdx < lastWordIdx) {
248 ASSERT_require(wordIdx==lastWordIdx);
249 ASSERT_require(wordIdx>firstWordIdx);
252 ASSERT_require(nRemaining > nBitsToLeft);
253 nbits = nRemaining - nBitsToLeft;
256 done =
processWord(processor, words[wordIdx], wordIdx==firstWordIdx ? offsetInWord : 0, nbits);
262 template<
class Processor,
class Word1,
class Word2>
264 ASSERT_require(
sizeof(Word1)==
sizeof(Word2));
268 ASSERT_require(range1.
size() == range2.
size());
273 size_t offsetInWord = bitIndex<Word2>(range2.
least());
274 const size_t nWordsTmp = numberOfWords<Word2>(offsetInWord + range2.
size());
275 SAWYER_VARIABLE_LENGTH_ARRAY(
typename RemoveConst<Word1>::Base, tmp, nWordsTmp);
277 nonoverlappingCopy(vec1, range1, tmp, tmpRange);
281 const size_t vec2WordOffset = wordIndex<Word2>(range2.
least());
282 size_t nRemaining = range2.
size();
284 for (
size_t wordIdx=0; !done && nRemaining > 0; ++wordIdx) {
285 ASSERT_require(wordIdx < nWordsTmp);
287 ASSERT_require(nbits > 0);
288 done =
processWord(processor, *
const_cast<Word1*
>(tmp+wordIdx), vec2[wordIdx+vec2WordOffset], offsetInWord, nbits);
294 conditionalCopy(tmp, tmpRange, vec1, range1);
298 template<
class Processor,
class Word1,
class Word2>
300 ASSERT_require(
sizeof(Word1)==
sizeof(Word2));
304 ASSERT_require(range1.
size() == range2.
size());
309 const size_t offsetInWord = bitIndex<Word2>(range2.
least());
310 const size_t nWordsTmp = numberOfWords<Word2>(offsetInWord + range2.
size());
311 SAWYER_VARIABLE_LENGTH_ARRAY(
typename RemoveConst<Word1>::Base, tmp, nWordsTmp);
313 nonoverlappingCopy(vec1, range1, tmp, tmpRange);
316 size_t nRemaining = range2.
size();
318 const size_t vec2WordOffset = wordIndex<Word2>(range2.
least());
319 for (
size_t wordIdx=nWordsTmp-1; !done && nRemaining>0; --wordIdx) {
324 }
else if (wordIdx < nWordsTmp-1) {
328 ASSERT_require(wordIdx==nWordsTmp-1);
329 ASSERT_require(wordIdx>0);
331 ASSERT_require(nRemaining > nBitsToLeft);
332 nbits = nRemaining - nBitsToLeft;
335 done =
processWord(processor, *
const_cast<Word1*
>(tmp+wordIdx), vec2[wordIdx+vec2WordOffset],
336 wordIdx==0 ? offsetInWord : 0, nbits);
341 conditionalCopy(tmp, tmpRange, vec1, range1);
344 template<
class Processor,
class Word>
346 const Word *vec1,
const BitRange &range1,
347 const Word *vec2,
const BitRange &range2,
349 traverse2(processor, vec1, range1, vec2, range2, dir);
352 template<
class Processor,
class Word>
354 const Word *vec1,
const BitRange &range1,
355 const Word *vec2,
const BitRange &range2,
357 traverse2(processor, vec1, range1, vec2, range2, dir);
359 template<
class Processor,
class Word>
361 const Word *vec1,
const BitRange &range1,
362 Word *vec2,
const BitRange &range2,
364 traverse2(processor, vec1, range1, vec2, range2, dir);
366 template<
class Processor,
class Word>
368 Word *vec1,
const BitRange &range1,
369 Word *vec2,
const BitRange &range2,
371 traverse2(processor, vec1, range1, vec2, range2, dir);
384 bool get(
const Word *words,
size_t idx) {
385 return 0 != (words[wordIndex<Word>(idx)] & bitMask<Word>(bitIndex<Word>(idx), 1));
390 bool operator()(Word &word,
size_t nbits) {
391 word &= ~bitMask<Word>(0, nbits);
407 bool operator()(Word &word,
size_t nbits) {
408 word |= bitMask<Word>(0, nbits);
436 bool operator()(
const Word &src, Word &dst,
size_t nbits) {
437 dst &= ~bitMask<Word>(0, nbits);
438 dst |= src & bitMask<Word>(0, nbits);
455 bool operator()(Word &w1, Word &w2,
size_t nbits) {
456 Word tmp = w1, mask = bitMask<Word>(0, nbits);
483 bool operator()(
const Word &w1, Word &w2,
size_t nbits) {
485 Word a = w1 & bitMask<Word>(0, nbits);
486 Word b = w2 & bitMask<Word>(0, nbits);
502 return visitor.wasEqv;
515 bool operator()(
const Word &word,
size_t nbits) {
516 if (0 != (word & bitMask<Word>(0, nbits))) {
517 for (
size_t i=0; i<nbits; ++i) {
518 if (0 != (word & bitMask<Word>(i, 1))) {
538 return range.
least() + *visitor.result;
547 bool operator()(
const Word &word,
size_t nbits) {
548 if (bitMask<Word>(0, nbits) != (word & bitMask<Word>(0, nbits))) {
549 for (
size_t i=0; i<nbits; ++i) {
550 if (0 == (word & bitMask<Word>(i, 1))) {
570 return range.
least() + *visitor.result;
579 bool operator()(
const Word &word,
size_t nbits) {
580 ASSERT_require(nbits <= offset);
582 if (0 != (word & bitMask<Word>(0, nbits))) {
583 for (
size_t i=nbits; i>0; --i) {
584 if (0 != (word & bitMask<Word>(i-1, 1))) {
585 result = offset + i-1;
603 return range.
least() + *visitor.result;
612 bool operator()(
const Word &word,
size_t nbits) {
613 ASSERT_require(nbits <= offset);
615 if (bitMask<Word>(0, nbits) != (word & bitMask<Word>(0, nbits))) {
616 for (
size_t i=nbits; i>0; --i) {
617 if (0 == (word & bitMask<Word>(i-1, 1))) {
618 result = offset + i-1;
636 return range.
least() + *visitor.result;
660 bool operator()(
const Word &word,
size_t nbits) {
661 if (0 != (word & bitMask<Word>(0, nbits))) {
662 for (
size_t i=0; i<nbits; ++i) {
663 if (0 != (word & bitMask<Word>(i, 1)))
678 return visitor.result;
685 bool operator()(
const Word &word,
size_t nbits) {
686 if (bitMask<Word>(0, nbits) != (word & bitMask<Word>(0, nbits))) {
687 for (
size_t i=0; i<nbits; ++i) {
688 if (0 == (word & bitMask<Word>(i, 1)))
703 return visitor.result;
711 bool operator()(
const Word &w1,
const Word &w2,
size_t nbits) {
712 Word mask = bitMask<Word>(0, nbits);
713 if ((w1 & mask) != (w2 & mask)) {
714 for (
size_t i=0; i<nbits; ++i) {
715 if ((w1 ^ w2) & bitMask<Word>(i, 1)) {
733 const Word *vec2,
const BitRange &range2) {
736 return visitor.result;
744 bool operator()(
const Word &w1,
const Word &w2,
size_t nbits) {
745 ASSERT_require(nbits <= offset);
747 Word mask = bitMask<Word>(0, nbits);
748 if ((w1 & mask) != (w2 & mask)) {
749 for (
size_t i=nbits; i>0; --i) {
750 if ((w1 ^ w2) & bitMask<Word>(i-1, 1)) {
751 result = offset + i-1;
767 const Word *vec2,
const BitRange &range2) {
770 return visitor.result;
794 if (nShift < range.
size()) {
795 size_t nbits = range.
size() - nShift;
799 copy(words, shiftedFrom, words, shiftedTo);
800 setValue(words, introduced, newBits);
812 if (nShift < range.
size()) {
813 size_t nbits = range.
size() - nShift;
817 copy(words, shiftedFrom, words, shiftedTo);
818 setValue(words, introduced, newBits);
844 nShift %= range.
size();
849 size_t nSavedWords = numberOfWords<Word>(nShift);
850 SAWYER_VARIABLE_LENGTH_ARRAY(Word, saved, nSavedWords);
857 copy(saved, savedRange, words, introduced);
868 nShift %= range.
size();
879 bool operator()(Word &word,
size_t nbits) {
880 word ^= bitMask<Word>(0, nbits);
896 bool operator()(
const Word &w1, Word &w2,
size_t nbits) {
897 w2 &= w1 | ~bitMask<Word>(0, nbits);
914 bool operator()(
const Word &w1, Word &w2,
size_t nbits) {
915 w2 |= w1 & bitMask<Word>(0, nbits);
932 bool operator()(
const Word &w1, Word &w2,
size_t nbits) {
933 w2 ^= w1 & bitMask<Word>(0, nbits);
958 ASSERT_require(8==
sizeof value);
963 size_t nbits = std::min(range.
size(), (
size_t)64);
965 size_t nTmpWords = numberOfWords<Word>(nbits);
966 SAWYER_VARIABLE_LENGTH_ARRAY(Word, tmp, nTmpWords);
967 for (
size_t i=0; i<nTmpWords; ++i)
972 if (range.
size() >= 64) {
984 boost::uint64_t result = 0;
985 ASSERT_require(8==
sizeof result);
988 size_t nbits = std::min(range.
size(), (
size_t)64);
989 size_t nTmpWords = numberOfWords<Word>(nbits);
990 SAWYER_VARIABLE_LENGTH_ARRAY(
typename RemoveConst<Word>::Base, tmp, nTmpWords);
995 for (
size_t i=0; i<nTmpWords; ++i)
1003 template<
class Word>
1004 boost::uint64_t
toInteger(
const Word *words,
size_t nbits) {
1005 boost::uint64_t result = 0;
1006 ASSERT_require(nbits <= 64);
1007 size_t nTmpWords = numberOfWords<Word>(nbits);
1008 for (
size_t i=0; i<nTmpWords; ++i)
1011 result &= ~((~(boost::uint64_t)0) << nbits);
1020 template<
class Word>
1022 boost::uint64_t u = toInteger<Word>(words, range);
1023 const size_t nBits = range.
size();
1024 if (nBits > 1 && nBits < 64) {
1025 bool isNegative = (u & (boost::uint64_t(1) << (nBits-1))) != 0;
1027 u |= boost::uint64_t(-1) << nBits;
1029 return boost::int64_t(u);
1036 template<
class Word>
1038 boost::uint64_t u = toInteger<Word>(words, nBits);
1039 if (nBits > 1 && nBits < 64) {
1040 bool isNegative = (u & (boost::uint64_t(1) << (nBits-1))) != 0;
1042 u |= boost::uint64_t(-1) << nBits;
1044 return boost::int64_t(u);
1047 template<
class Word>
1051 bool operator()(Word &word,
size_t nbits) {
1052 ASSERT_require(carry);
1053 Word mask = bitMask<Word>(0, nbits);
1054 Word arg1 = word & mask;
1055 Word
sum = arg1 + 1;
1058 carry = (
sum & mask) < arg1;
1066 template<
class Word>
1070 return visitor.carry;
1073 template<
class Word>
1077 bool operator()(Word &word,
size_t nbits) {
1078 ASSERT_require(borrowed);
1079 Word mask = bitMask<Word>(0, nbits);
1080 Word arg1 = word & mask;
1082 Word difference = (arg1 - 1) & mask;
1093 template<
class Word>
1097 return visitor.borrowed;
1103 template<
class Word>
1109 template<
class Word>
1112 AddBits(
bool carry): carry(carry) {}
1113 bool operator()(
const Word &w1, Word &w2,
size_t nbits) {
1114 Word mask = bitMask<Word>(0, nbits);
1115 Word addend1(carry ? 1 : 0);
1116 Word addend2(w1 & mask);
1117 Word addend3(w2 & mask);
1118 Word
sum = addend1 + addend2 + addend3;
1122 carry =
sum < addend2 || (
sum==addend2 && carry);
1124 carry = 0 != (
sum & bitMask<Word>(nbits, 1));
1134 template<
class Word>
1138 return visitor.carry;
1147 template<
class Word>
1149 size_t nTempWords = numberOfWords<Word>(range1.
size());
1150 SAWYER_VARIABLE_LENGTH_ARRAY(Word, temp, nTempWords);
1152 copy(vec1, range1, temp, tempRange);
1154 return add(temp, tempRange, vec2, range2,
true);
1163 template<
class Word>
1167 }
else if (range1.
isEmpty()) {
1168 clear(vec2, range2);
1170 }
else if (range1.
size() < range2.
size()) {
1176 ASSERT_require(range1.
size() >= range2.
size());
1178 copy(vec1, copyFrom, vec2, range2);
1186 template<
class Word>
1189 const size_t nWords = numberOfWords<Word>(range.
size());
1191 SAWYER_VARIABLE_LENGTH_ARRAY(Word, part, nWords);
1192 copy(vec, range, part, partRange);
1195 add(part, partRange, vec, range);
1205 template<
class Word>
1210 template<
class Word>
1214 bool operator()(
const Word &w1,
const Word &w2,
size_t nbits) {
1215 Word mask = bitMask<Word>(0, nbits);
1216 Word tmp1 = w1 & mask;
1217 Word tmp2 = w2 & mask;
1221 }
else if (tmp1 > tmp2) {
1236 template<
class Word>
1240 }
else if (range1.
isEmpty()) {
1242 }
else if (range2.
isEmpty()) {
1244 }
else if (range1.
size() < range2.
size()) {
1249 return compare(vec1, range1, vec2, lo);
1250 }
else if (range1.
size() > range2.
size()) {
1255 return compare(vec1, lo, vec2, range2);
1258 ASSERT_require(range1.
size() == range2.
size());
1261 return visitor.result;
1271 template<
class Word>
1275 }
else if (range1.
isEmpty()) {
1277 return *mssb == range2.
greatest() ? 1 : -1;
1281 }
else if (range2.
isEmpty()) {
1283 return *mssb == range1.
greatest() ? -1 : 1;
1287 }
else if (range1.
size() < range2.
size()) {
1291 if (!neg1 && !neg2) {
1292 return compare(vec1, range1, vec2, range2);
1293 }
else if (neg1 && neg2) {
1304 }
else if (range1.
size() > range2.
size()) {
1307 ASSERT_require(range1.
size()==range2.
size());
1310 if (!neg1 && !neg2) {
1311 return compare(vec1, range1, vec2, range2);
1312 }
else if (neg1 && neg2) {
1314 return get(vec1, range1.
least() + *diff) ? 1 : -1;
1331 template<
class Word,
size_t bitsPerDigit>
1335 std::string reversed;
1337 ToString(): remaining(0), nremaining(0) {
1338 ASSERT_require(bitsPerDigit >= 1 && bitsPerDigit <= 4);
1342 bool operator()(
const Word &word,
size_t nbits) {
1343 static const char digits[] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f'};
1344 Word tmp = word & bitMask<Word>(0, nbits);
1345 ASSERT_require(nremaining < bitsPerDigit);
1346 while (nremaining+nbits >= bitsPerDigit) {
1347 size_t nrem = std::min(nremaining, bitsPerDigit);
1348 size_t nnew = bitsPerDigit - nrem;
1349 Word digit = (remaining & bitMask<Word>(0, nrem)) | ((tmp & bitMask<Word>(0, nnew)) << nrem);
1350 reversed += digits[digit];
1360 std::string result() {
1361 if (nremaining > 0) {
1362 ASSERT_require(nremaining <= 3);
1363 reversed +=
'0' + (remaining & bitMask<Word>(0, nremaining));
1367 std::swap(s, reversed);
1368 std::reverse(s.begin(), s.end());
1379 template<
class Word>
1383 return visitor.result();
1391 template<
class Word>
1395 return visitor.result();
1403 template<
class Word>
1407 return visitor.result();
1414 template<
class Word>
1415 Word charToDigit(
char ch) {
1417 if (ch >=
'0' && ch <=
'9') {
1419 }
else if (ch >=
'a' && ch <=
'f') {
1420 digit = ch -
'a' + 10;
1421 }
else if (ch >=
'A' && ch <=
'F') {
1422 digit = ch -
'A' + 10;
1429 template<
class Word,
size_t bitsPerDigit>
1430 void fromString(Word *vec,
const BitRange &range,
const std::string &input) {
1431 ASSERT_require(bitsPerDigit >= 1 && bitsPerDigit <= 4);
1432 ASSERT_require(bitsPerDigit <= bitsPerWord<Word>::value);
1435 for (
size_t idx=0; idx<input.size(); ++idx) {
1436 if (
'_'!=input[idx] && charToDigit<Word>(input[idx]) >= Word(1) << bitsPerDigit) {
1437 throw std::runtime_error(std::string(
"invalid character '") + input[idx] +
"' at index " +
1438 boost::lexical_cast<std::string>(idx) +
" in base-" +
1439 boost::lexical_cast<std::string>(1 << bitsPerDigit) +
" input string");
1445 for (
size_t idx=input.size(); idx>0 && offset<range.size(); --idx) {
1446 if (
'_'!=input[idx-1]) {
1447 Word digit = charToDigit<Word>(input[idx-1]);
1448 size_t nbits = std::min(bitsPerDigit, range.size()-offset);
1451 offset += bitsPerDigit;
1456 if (offset < range.size())
1467 template<
class Word>
1470 boost::uint64_t v = 0;
1471 bool hadOverflow =
false;
1472 BOOST_FOREACH (
char ch, input) {
1474 boost::uint64_t tmp = v * 10 + (ch -
'0');
1480 }
else if (ch !=
'_') {
1481 throw std::runtime_error(
"invalid decimal digit \"" + std::string(1, ch) +
"\"");
1490 const size_t nWords = numberOfWords<Word>(range.
size());
1491 SAWYER_VARIABLE_LENGTH_ARRAY(Word, accumulator, nWords);
1492 SAWYER_VARIABLE_LENGTH_ARRAY(Word, digit, nWords);
1494 BOOST_FOREACH (
char ch, input) {
1497 add(digit, accumulatorRange, accumulator, accumulatorRange);
1499 copy(accumulator, accumulatorRange, vec, range);
1509 template<
class Word>
1511 fromString<Word, 4>(vec, range, input);
1520 template<
class Word>
1522 fromString<Word, 3>(vec, range, input);
1531 template<
class Word>
1533 fromString<Word, 1>(vec, range, input);