mirror of https://github.com/mosra/magnum.git
4 changed files with 400 additions and 0 deletions
@ -0,0 +1,232 @@
|
||||
#ifndef Magnum_Math_BoolVector_h |
||||
#define Magnum_Math_BoolVector_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class Magnum::Math::BoolVector |
||||
*/ |
||||
|
||||
#include <cstdint> |
||||
#include <Utility/Debug.h> |
||||
|
||||
namespace Magnum { namespace Math { |
||||
|
||||
/**
|
||||
@brief %Vector storing boolean values |
||||
@tparam size Bit count |
||||
|
||||
Result of component-wise comparison from Vector. The boolean values are stored |
||||
as bits in array of unsigned bytes, unused bits have undefined value which |
||||
doesn't affect comparison or all() / none() / any() functions. See also |
||||
@ref matrix-vector for brief introduction. |
||||
*/ |
||||
template<std::size_t size> class BoolVector { |
||||
static_assert(size != 0, "BoolVector cannot have zero elements"); |
||||
|
||||
public: |
||||
static const std::size_t Size = size; /**< @brief %Vector size */ |
||||
static const std::size_t DataSize = (size-1)/8+1; /**< @brief %Vector storage size */ |
||||
|
||||
/** @brief Construct boolean with one value for all elements */ |
||||
inline static BoolVector<size> from(bool value) { |
||||
BoolVector<size> out; |
||||
|
||||
for(std::size_t i = 0; i != size; ++i) |
||||
out._data[i] = (value ? FullSegmentMask : 0); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
/** @brief Construct zero-filled boolean vector */ |
||||
inline constexpr BoolVector(): _data() {} |
||||
|
||||
/** @brief Construct boolean vector from given values */ |
||||
template<class ...U> inline constexpr BoolVector(std::uint8_t first, U... next): _data{first, std::uint8_t(next)...} { |
||||
static_assert(sizeof...(next)+1 == DataSize, "Improper number of arguments passed to BoolVector constructor"); |
||||
} |
||||
|
||||
/** @brief Copy constructor */ |
||||
inline constexpr BoolVector(const BoolVector<size>&) = default; |
||||
|
||||
/** @brief Copy assignment */ |
||||
inline BoolVector<size>& operator=(const BoolVector<size>&) = default; |
||||
|
||||
/**
|
||||
* @brief Raw data |
||||
* @return %Array of DataSize length |
||||
* |
||||
* @see operator[](), set() |
||||
*/ |
||||
inline std::uint8_t* data() { return _data; } |
||||
inline constexpr const std::uint8_t* data() const { return _data; } /**< @overload */ |
||||
|
||||
/** @brief Bit at given position */ |
||||
inline constexpr bool operator[](std::size_t i) const { |
||||
return (_data[i/8] >> i%8) & 0x01; |
||||
} |
||||
|
||||
/** @brief Set bit at given position */ |
||||
inline BoolVector<size>& set(std::size_t i, bool value) { |
||||
_data[i/8] |= ((value & 0x01) << i%8); |
||||
return *this; |
||||
} |
||||
|
||||
/** @brief Equality comparison */ |
||||
inline bool operator==(const BoolVector<size>& other) const { |
||||
for(std::size_t i = 0; i != size/8; ++i) |
||||
if(_data[i] != other._data[i]) return false; |
||||
|
||||
/* Check last segment */ |
||||
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != (other._data[DataSize-1] & LastSegmentMask)) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** @brief Non-equality comparison */ |
||||
inline bool operator!=(const BoolVector<size>& other) const { |
||||
return !operator==(other); |
||||
} |
||||
|
||||
/** @brief Whether all bits are set */ |
||||
bool all() const { |
||||
/* Check all full segments */ |
||||
for(std::size_t i = 0; i != size/8; ++i) |
||||
if(_data[i] != FullSegmentMask) return false; |
||||
|
||||
/* Check last segment */ |
||||
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != LastSegmentMask) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** @brief Whether no bits are set */ |
||||
bool none() const { |
||||
/* Check all full segments */ |
||||
for(std::size_t i = 0; i != size/8; ++i) |
||||
if(_data[i]) return false; |
||||
|
||||
/* Check last segment */ |
||||
if(size%8 && (_data[DataSize-1] & LastSegmentMask)) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** @brief Whether any bit is set */ |
||||
inline bool any() const { |
||||
return !none(); |
||||
} |
||||
|
||||
/** @brief Bitwise inversion */ |
||||
inline BoolVector<size> operator~() const { |
||||
BoolVector<size> out; |
||||
|
||||
for(std::size_t i = 0; i != DataSize; ++i) |
||||
out._data[i] = ~_data[i]; |
||||
|
||||
return out; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Bitwise AND and assign |
||||
* |
||||
* The computation is done in-place. |
||||
*/ |
||||
inline BoolVector<size>& operator&=(const BoolVector<size>& other) { |
||||
for(std::size_t i = 0; i != DataSize; ++i) |
||||
_data[i] &= other._data[i]; |
||||
|
||||
return *this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Bitwise AND |
||||
* |
||||
* @see operator&=() |
||||
*/ |
||||
inline BoolVector<size> operator&(const BoolVector<size>& other) const { |
||||
return BoolVector<size>(*this) &= other; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Bitwise OR and assign |
||||
* |
||||
* The computation is done in-place. |
||||
*/ |
||||
inline BoolVector<size>& operator|=(const BoolVector<size>& other) { |
||||
for(std::size_t i = 0; i != DataSize; ++i) |
||||
_data[i] |= other._data[i]; |
||||
|
||||
return *this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Bitwise OR |
||||
* |
||||
* @see operator|=() |
||||
*/ |
||||
inline BoolVector<size> operator|(const BoolVector<size>& other) const { |
||||
return BoolVector<size>(*this) |= other; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Bitwise XOR and assign |
||||
* |
||||
* The computation is done in-place. |
||||
*/ |
||||
inline BoolVector<size>& operator^=(const BoolVector<size>& other) { |
||||
for(std::size_t i = 0; i != DataSize; ++i) |
||||
_data[i] ^= other._data[i]; |
||||
|
||||
return *this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Bitwise XOR |
||||
* |
||||
* @see operator^=() |
||||
*/ |
||||
inline BoolVector<size> operator^(const BoolVector<size>& other) const { |
||||
return BoolVector<size>(*this) ^= other; |
||||
} |
||||
|
||||
private: |
||||
enum: std::uint8_t { |
||||
FullSegmentMask = 0xFF, |
||||
LastSegmentMask = (1 << size%8) - 1 |
||||
}; |
||||
|
||||
std::uint8_t _data[(size-1)/8+1]; |
||||
}; |
||||
|
||||
/** @debugoperator{Magnum::Math::BoolVector} */ |
||||
template<std::size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const BoolVector<size>& value) { |
||||
debug << "BoolVector("; |
||||
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); |
||||
for(std::size_t i = 0; i != size; ++i) { |
||||
if(i && !(i%8)) debug << " "; |
||||
debug << (value[i] ? "1" : "0"); |
||||
} |
||||
debug << ")"; |
||||
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); |
||||
return debug; |
||||
} |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright © 1910, 1911, 1912 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <TestSuite/Tester.h> |
||||
|
||||
#include "Math/BoolVector.h" |
||||
|
||||
namespace Magnum { namespace Math { namespace Test { |
||||
|
||||
class BoolVectorTest: public Corrade::TestSuite::Tester { |
||||
public: |
||||
explicit BoolVectorTest(); |
||||
|
||||
void constructDefault(); |
||||
void constructOneValue(); |
||||
void data(); |
||||
|
||||
void compare(); |
||||
void compareUndefined(); |
||||
void all(); |
||||
void none(); |
||||
void any(); |
||||
|
||||
void bitInverse(); |
||||
void bitAndOrXor(); |
||||
|
||||
void debug(); |
||||
}; |
||||
|
||||
static_assert(BoolVector<15>::DataSize == 2, "Improper DataSize"); |
||||
static_assert(BoolVector<16>::DataSize == 2, "Improper DataSize"); |
||||
static_assert(BoolVector<17>::DataSize == 3, "Improper DataSize"); |
||||
|
||||
typedef Math::BoolVector<19> BoolVector19; |
||||
|
||||
BoolVectorTest::BoolVectorTest() { |
||||
addTests(&BoolVectorTest::constructDefault, |
||||
&BoolVectorTest::constructOneValue, |
||||
&BoolVectorTest::data, |
||||
|
||||
&BoolVectorTest::compare, |
||||
&BoolVectorTest::compareUndefined, |
||||
&BoolVectorTest::all, |
||||
&BoolVectorTest::none, |
||||
&BoolVectorTest::any, |
||||
|
||||
&BoolVectorTest::bitInverse, |
||||
&BoolVectorTest::bitAndOrXor, |
||||
|
||||
&BoolVectorTest::debug); |
||||
} |
||||
|
||||
void BoolVectorTest::constructDefault() { |
||||
CORRADE_COMPARE(BoolVector19(), BoolVector19(0x00, 0x00, 0x00)); |
||||
} |
||||
|
||||
void BoolVectorTest::constructOneValue() { |
||||
CORRADE_COMPARE(BoolVector19::from(false), BoolVector19(0x00, 0x00, 0x00)); |
||||
CORRADE_COMPARE(BoolVector19::from(true), BoolVector19(0xff, 0xff, 0x07)); |
||||
} |
||||
|
||||
void BoolVectorTest::data() { |
||||
BoolVector19 a(0x08, 0x03, 0x04); |
||||
|
||||
CORRADE_VERIFY(!a[0] && !a[1] && !a[2]); |
||||
CORRADE_VERIFY(a[3]); |
||||
CORRADE_VERIFY(!a[4] && !a[5] && !a[6] && !a[7]); |
||||
CORRADE_VERIFY(a[8]); |
||||
CORRADE_VERIFY(a[9]); |
||||
CORRADE_VERIFY(!a[10] && !a[11] && !a[12] && !a[13] && !a[14] && !a[15] && !a[16] && !a[17]); |
||||
CORRADE_VERIFY(a[18]); |
||||
|
||||
a.set(15, true); |
||||
CORRADE_VERIFY(a[15]); |
||||
|
||||
CORRADE_COMPARE(a, BoolVector19(0x08, 0x83, 0x04)); |
||||
} |
||||
|
||||
void BoolVectorTest::compare() { |
||||
BoolVector19 a(0xa5, 0x5f, 0x07); |
||||
CORRADE_VERIFY(a == a); |
||||
|
||||
/* Change in full segments */ |
||||
BoolVector19 b(0xa3, 0x5f, 0x07); |
||||
BoolVector19 c(0xa5, 0x98, 0x07); |
||||
CORRADE_VERIFY(a != b); |
||||
CORRADE_VERIFY(a != c); |
||||
|
||||
/* Change in last bit */ |
||||
BoolVector19 d(0xa5, 0x5f, 0x06); |
||||
CORRADE_VERIFY(a != d); |
||||
} |
||||
|
||||
void BoolVectorTest::compareUndefined() { |
||||
BoolVector19 a(0xa5, 0x5f, 0x07); |
||||
|
||||
/* Change in unused part of last segment */ |
||||
BoolVector19 b(0xa5, 0x5f, 0x0f); |
||||
CORRADE_VERIFY(a == b); |
||||
|
||||
/* Change in used part of last segment */ |
||||
BoolVector19 c(0xa5, 0x5f, 0x03); |
||||
CORRADE_VERIFY(a != c); |
||||
} |
||||
|
||||
void BoolVectorTest::all() { |
||||
CORRADE_VERIFY(BoolVector19(0xff, 0xff, 0x07).all()); |
||||
|
||||
/* Last segment - bit in used and unused part */ |
||||
CORRADE_VERIFY(BoolVector19(0xff, 0xff, 0x0f).all()); |
||||
CORRADE_VERIFY(!BoolVector19(0xff, 0xff, 0x04).all()); |
||||
} |
||||
|
||||
void BoolVectorTest::none() { |
||||
CORRADE_VERIFY(BoolVector19(0x00, 0x00, 0x00).none()); |
||||
|
||||
/* Last segment - bit in used and unused part */ |
||||
CORRADE_VERIFY(BoolVector19(0x00, 0x00, 0x08).none()); |
||||
CORRADE_VERIFY(!BoolVector19(0x00, 0x00, 0x04).none()); |
||||
} |
||||
|
||||
void BoolVectorTest::any() { |
||||
CORRADE_VERIFY(BoolVector19(0x00, 0x01, 0x00).any()); |
||||
|
||||
/* Last segment - bit in used and unused part */ |
||||
CORRADE_VERIFY(BoolVector19(0x00, 0x00, 0x04).any()); |
||||
CORRADE_VERIFY(!BoolVector19(0x00, 0x00, 0x08).any()); |
||||
} |
||||
|
||||
void BoolVectorTest::bitInverse() { |
||||
CORRADE_COMPARE(~BoolVector19(0xa5, 0x5f, 0x03), BoolVector19(0x5a, 0xa0, 0x04)); |
||||
} |
||||
|
||||
void BoolVectorTest::bitAndOrXor() { |
||||
BoolVector19 a(0xa5, 0x5f, 0x03); |
||||
BoolVector19 b(0x37, 0xf3, 0x06); |
||||
|
||||
CORRADE_COMPARE(a & b, BoolVector19(0x25, 0x53, 0x02)); |
||||
CORRADE_COMPARE(a | b, BoolVector19(0xb7, 0xff, 0x07)); |
||||
CORRADE_COMPARE(a ^ b, BoolVector19(0x92, 0xac, 0x05)); |
||||
} |
||||
|
||||
void BoolVectorTest::debug() { |
||||
std::ostringstream o; |
||||
|
||||
Corrade::Utility::Debug(&o) << BoolVector19(0x25, 0x53, 0x02); |
||||
|
||||
CORRADE_COMPARE(o.str(), "BoolVector(10100100 11001010 010)\n"); |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Math::Test::BoolVectorTest) |
||||
Loading…
Reference in new issue