From d8e500b2d785b6c8e12ceb25efe68c32aad46a8b Mon Sep 17 00:00:00 2001 From: Determinant Date: Fri, 13 Jul 2018 14:35:03 -0400 Subject: finish Bits impl --- .gitignore | 1 + include/salticidae/ref.h | 1 + include/salticidae/stream.h | 66 ++++++++++++++++++++++++++----------- include/salticidae/type.h | 17 ++++++++++ test/.gitignore | 1 + test/CMakeLists.txt | 3 ++ test/test_stream.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 test/test_stream.cpp diff --git a/.gitignore b/.gitignore index 475a195..0b0d2ec 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ src/*.swp *.so *.gch /Makefile +core diff --git a/include/salticidae/ref.h b/include/salticidae/ref.h index c0b77a3..7239402 100644 --- a/include/salticidae/ref.h +++ b/include/salticidae/ref.h @@ -131,6 +131,7 @@ class BoxObj: public _BoxObj { BoxObj(BoxObj &&other): base_t(std::move(other)) {} T &operator[](size_t idx) { return base_t::obj[idx]; } + const T &operator[] (size_t idx) const { return base_t::obj[idx]; } }; template, typename T_, typename D_> diff --git a/include/salticidae/stream.h b/include/salticidae/stream.h index b5e0757..5b7e936 100644 --- a/include/salticidae/stream.h +++ b/include/salticidae/stream.h @@ -271,36 +271,36 @@ class Blob { }; template -class Bits { +class _Bits { using _impl_type = T; - static const size_t bit_per_datum = sizeof(_impl_type) * 8; + static const uint32_t bit_per_datum = sizeof(_impl_type) * 8; + static const uint32_t shift_per_datum = log2::value; BoxObj<_impl_type[]> data; - size_t nbits; - size_t ndata; + uint32_t nbits; + uint32_t ndata; public: - Bits(): data(nullptr) {} - Bits(const bytearray_t &arr) { + _Bits(): data(nullptr) {} + _Bits(const bytearray_t &arr) { load(&*arr.begin(), arr.size()); } - Bits(const uint8_t *arr, size_t len) { load(arr, len); } - Bits(size_t nbits): nbits(nbits) { + _Bits(const uint8_t *arr, uint32_t len) { load(arr, len); } + _Bits(uint32_t nbits): nbits(nbits) { ndata = (nbits + bit_per_datum - 1) / bit_per_datum; data = new _impl_type[ndata]; } - ~Bits() {} + ~_Bits() {} - void load(const uint8_t *arr, size_t len) { + void load(const uint8_t *arr, uint32_t len) { nbits = len * 8; - ndata = (len + sizeof(_impl_type) - 1) / - sizeof(_impl_type); + ndata = (nbits + bit_per_datum - 1) / bit_per_datum; data = new _impl_type[ndata]; uint8_t *end = arr + len; - for (_impl_type *ptr = data; ptr < data + ndata;) + for (_impl_type *ptr = data.get(); ptr < data.get() + ndata;) { _impl_type x = 0; for (unsigned j = 0, k = 0; j < sizeof(_impl_type); j++, k += 8) @@ -317,24 +317,24 @@ class Bits { s << htole(nbits); if (data) { - for (const _impl_type *ptr = data; ptr < data + ndata; ptr++) + for (const _impl_type *ptr = data.get(); ptr < data.get() + ndata; ptr++) s << htole(*ptr); } else { - for (const _impl_type *ptr = data; ptr < data + ndata; ptr++) + for (const _impl_type *ptr = data.get(); ptr < data.get() + ndata; ptr++) s << htole((_impl_type)0); } } void unserialize(DataStream &s) { - _impl_type x; - s >> x; - nbits = letoh(x); + s >> nbits; + nbits = letoh(nbits); ndata = (nbits + bit_per_datum - 1) / bit_per_datum; data = new _impl_type[ndata]; - for (_impl_type *ptr = data; ptr < data + ndata; ptr++) + for (_impl_type *ptr = data.get(); ptr < data.get() + ndata; ptr++) { + _impl_type x; s >> x; *ptr = letoh(x); } @@ -345,8 +345,36 @@ class Bits { s << *this; return std::move(s); } + + uint8_t get(uint32_t idx) const { + return (data[idx >> shift_per_datum] >> + (idx & (bit_per_datum - 1))) & 1; + } + + void set(uint32_t idx) { + auto i = idx >> shift_per_datum; + auto pos = idx & (bit_per_datum - 1); + data[i] ^= ((data[i] >> pos) ^ 1) << pos; + } + + void unset(uint32_t idx) { + auto i = idx >> shift_per_datum; + auto pos = idx & (bit_per_datum - 1); + data[i] ^= (data[i] >> pos) << pos; + } + + void flip(uint32_t idx) { + auto i = idx >> shift_per_datum; + auto pos = idx & (bit_per_datum - 1); + data[i] ^= ((_impl_type)1) << pos; + } + + uint8_t operator[](uint32_t idx) const { return get(idx); } + + uint32_t size() const { return nbits; } }; +using Bits = _Bits<>; const size_t ENT_HASH_LENGTH = 256 / 8; diff --git a/include/salticidae/type.h b/include/salticidae/type.h index d5834a5..13975a5 100644 --- a/include/salticidae/type.h +++ b/include/salticidae/type.h @@ -65,6 +65,23 @@ struct is_ranged().begin()), decltype(std::declval().end())>> : std::true_type {}; +template +struct log2 { + enum { + value = 1 + log2::value + }; +}; + +template<> +struct log2<0> { + enum { value = 0 }; +}; + +template<> +struct log2<1> { + enum { value = 0 }; +}; + } #endif diff --git a/test/.gitignore b/test/.gitignore index b308815..9b5c5f5 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,2 +1,3 @@ test_msg +test_stream Makefile diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 423229b..bedaaa3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,3 +22,6 @@ add_executable(test_msg test_msg.cpp) target_link_libraries(test_msg salticidae) + +add_executable(test_stream test_stream.cpp) +target_link_libraries(test_stream salticidae) diff --git a/test/test_stream.cpp b/test/test_stream.cpp new file mode 100644 index 0000000..0e05146 --- /dev/null +++ b/test/test_stream.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2018 Cornell University. + * + * Author: Ted Yin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "salticidae/stream.h" + +using salticidae::DataStream; +using salticidae::get_hash; +using salticidae::get_hex; +using salticidae::Bits; + +void print(const Bits &a, int n) { + for (int i = 0; i < n; i++) + printf("%d", a.get(i)); + puts(""); +} + +int main() { + int n = 80; + Bits a(n); + for (int i = 0; i < n; i++) + { + a.set(i); + print(a, n); + } + for (int i = n - 1; i >= 0; i--) + { + a.unset(i); + print(a, n); + } + std::vector idxs; + for (int i = 0; i < 1000; i++) + { + idxs.push_back(rand() % n); + a.flip(idxs.back()); + print(a, n); + } + for (auto idx: idxs) + { + a.flip(idx); + print(a, n); + } + for (int i = 0; i < n; i++) + if (i & 1) a.set(i); + print(a, n); + for (int i = 0; i < n; i++) + if (i & 1) a.unset(i); + else a.set(i); + print(a, n); + printf("%s size: %d\n", get_hex(a).c_str(), a.size()); + DataStream s; + s << a; + Bits b; + s >> b; + printf("%s\n", get_hex(b).c_str()); + print(b, b.size()); + return 0; +} -- cgit v1.2.3-70-g09d2