and演算とnot演算が実装されたBitboardクラスのコードを以下に示す。このクラスを使うと、b0 & ~b1 のように書くことは可能になる。しかし、_mm_andnot_si128()を使った高速化ができないという欠点がある。
class Bitboard { __m128i m128i_; public: Bitboard operator~() const { __m128i temp; const __m128i mask = _mm_cmpeq_epi64(temp, temp); return Bitboard{ _mm_xor_si128(m128i_, mask) }; } Bitboard operator&(const Bitboard& b) const { return Bitboard{ _mm_and_si128(m128i_, b.m128i_) }; } uint64_t operator[](const size_t i) const { return m128i_.m128i_u64[i]; } constexpr explicit Bitboard(const __m128i& i) : m128i_(i) {} };
そこで、内部にNot構造体を持つことにする。not演算子があってもすぐに否定演算をすると決めつけず、判断を保留してand演算子に出会えば_mm_andnot_si128()が使われる(要するに使えるところでは_mm_andnot_si128()を使うようにコンパイルしてくれる)。
class Bitboard { __m128i m128i_; struct Not { const __m128i not_m128i_; //~b0 & b1 Bitboard operator&(const Bitboard& b) const { return Bitboard{ _mm_andnot_si128(not_m128i_, b.m128i_) }; } //通常のnot operator Bitboard() const { __m128i temp; const __m128i mask = _mm_cmpeq_epi64(temp, temp); return Bitboard{ _mm_xor_si128(not_m128i_, mask) }; } explicit Not(const Bitboard& b) : not_m128i_(b.m128i_) {} }; public: //ここでは計算せずNot構造体を返す Bitboard::Not operator~() const { return Bitboard::Not{ *this }; } //b0 & ~b1 Bitboard operator&(const Bitboard::Not& not_b) const { return Bitboard{ _mm_andnot_si128(not_b.not_m128i_, m128i_) }; } Bitboard operator&(const Bitboard& b) const { return Bitboard{ _mm_and_si128(m128i_, b.m128i_) }; } uint64_t operator[](const size_t i) const { return m128i_.m128i_u64[i]; } constexpr explicit Bitboard(const __m128i& i) : m128i_(i) {} }; //気軽に下のように書けてとても便利! Bitboard attackBB = attacks_bb(C, from, P, pos.occupied_) & ~pos.byColorBB_[C];//_mm_andnot_si128()が使われる