test-client-godot/modules/bitset/bitset.cpp
2020-04-10 18:09:06 +02:00

194 lines
6.1 KiB
C++

/*
* Class BitSet
Copyright (C) 2019 AleaJactaEst
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Build :
scons platform=linux bits=64
*/
// #include <iostream>
#include "bitset.h"
#define BITSET_SIZE 32
void BitSet::_bind_methods()
{
ClassDB::bind_method(D_METHOD("size"), &BitSet::size);
ClassDB::bind_method(D_METHOD("resize", "num_bits"), &BitSet::resize);
ClassDB::bind_method(D_METHOD("clear"), &BitSet::clear);
ClassDB::bind_method(D_METHOD("clear_data"), &BitSet::clear_data);
ClassDB::bind_method(D_METHOD("set_bit", "bit_number"), &BitSet::set_bit);
ClassDB::bind_method(D_METHOD("clear_bit", "bit_number"), &BitSet::clear_bit);
ClassDB::bind_method(D_METHOD("write", "bit_number", "value"), &BitSet::write);
ClassDB::bind_method(D_METHOD("read", "bit_number"), &BitSet::read);
ClassDB::bind_method(D_METHOD("write_serial", "msgout"), &BitSet::write_serial);
ClassDB::bind_method(D_METHOD("read_serial", "msgin"), &BitSet::read_serial);
ClassDB::bind_method(D_METHOD("show"), &BitSet::show);
}
BitSet::BitSet()
{
this->_num_bits = 8;
this->_size_byte = 1;
this->_mask_last = 0;
this->_data = new uint32_t[1];
}
BitSet::~BitSet()
{
// add your cleanup here
if ( this->_data != nullptr )
{
delete [] this->_data;
this->_data = nullptr;
}
}
int BitSet::size()
{
return this->_size_byte;
}
#include "core/os/os.h"
void BitSet::resize(uint32_t num_bits)
{
uint32_t n_last_bits;
uint32_t new_size_byte = (num_bits + BITSET_SIZE - 1) / BITSET_SIZE;
OS::get_singleton()->print((String("INFO [") + String(__FILE__) + String(":") + String(uitos(__LINE__)) + String("] Resize") + String("\n")).utf8());
new_size_byte = (num_bits + BITSET_SIZE - 1) / BITSET_SIZE;
if (this->_size_byte != new_size_byte )
{
this->_size_byte = new_size_byte;
delete [] this->_data;
this->_data = new uint32_t[this->_size_byte];
if ( this->_data == nullptr )
{
ERR_PRINT("[BitSet::set_bit] Allocation error");
throw "Allocation error";
}
}
this->_num_bits = num_bits;
n_last_bits = this->_num_bits & (BITSET_SIZE - 1);
if ( n_last_bits == 0 )
this->_mask_last = ~0;
else
this->_mask_last = (1 << n_last_bits) - 1;
this->clear_data();
}
void BitSet::clear()
{
OS::get_singleton()->print((String("INFO [") + String(__FILE__) + String(":") + String(uitos(__LINE__)) + String("] Clear") + String("\n")).utf8());
this->resize(1);
}
void BitSet::clear_data()
{
OS::get_singleton()->print((String("INFO [") + String(__FILE__) + String(":") + String(uitos(__LINE__)) + String("] clear_data") + String("\n")).utf8());
for(uint32_t i = 0;i < this->_size_byte; ++i)
this->_data[i] = 0;
}
void BitSet::set_bit(uint32_t bit_number)
{
OS::get_singleton()->print((String("INFO [") + String(__FILE__) + String(":") + String(uitos(__LINE__)) + String("] set_bit") + String("\n")).utf8());
if (bit_number >= this->_num_bits)
{
ERR_PRINT("[BitSet::set_bit] Out of range (size:" + itos(this->_size_byte) + ", pos:" + itos(bit_number) + ")" );
throw "Out of range";
}
uint32_t mask = bit_number & (BITSET_SIZE - 1);
mask = 1 << mask;
this->_data[bit_number>>5] |= mask;
}
void BitSet::clear_bit(uint32_t bit_number)
{
OS::get_singleton()->print((String("INFO [") + String(__FILE__) + String(":") + String(uitos(__LINE__)) + String("] clear_bit") + String("\n")).utf8());
if (bit_number >= this->_num_bits)
{
ERR_PRINT("[BitSet::clear_bit] Out of range (size:" + itos(this->_size_byte) + ", pos:" + itos(bit_number) + ")" );
throw "Out of range";
}
uint32_t mask = bit_number & (BITSET_SIZE - 1);
mask = 1 << mask;
this->_data[bit_number>>5] &= ~ mask;
}
void BitSet::write(uint32_t bit_number, bool value)
{
if (bit_number >= this->_num_bits)
{
ERR_PRINT("[BitSet::put] Out of range (size:" + itos(this->_size_byte) + ", pos:" + itos(bit_number) + ")" );
throw "Out of range";
}
if ( value == true )
this->set_bit(bit_number);
else
this->clear_bit(bit_number);
}
bool BitSet::read(uint32_t bit_number)
{
if (bit_number >= this->_num_bits)
{
ERR_PRINT("[BitSet::pull] Out of range (size:" + itos(this->_size_byte) + ", pos:" + itos(bit_number) + ")" );
throw "Out of range";
}
uint32_t mask = bit_number & (BITSET_SIZE - 1);
mask = 1 << mask;
return (this->_data[bit_number>>5] & mask) != 0;
}
void BitSet::write_serial(Ref<BitStream> msgout)
{
uint8_t current_version = 0;
msgout->put_uint8(current_version);
msgout->put_uint32(this->_num_bits);
// _size_byte est lié à _num_bits dommage que l'on envoie celui-la
msgout->put_uint32(this->_size_byte);
for(uint32_t i = 0;i < this->_size_byte; ++i)
msgout->put_uint32(this->_data[i]);
}
void BitSet::read_serial(Ref<BitStream> msgin)
{
uint8_t current_version = msgin->get_sint8();
uint8_t num_bits;
switch ( current_version )
{
case 0:
num_bits = msgin->get_uint32();
this->resize(num_bits);
for(uint32_t i = 0;i < this->_size_byte; ++i)
this->_data[i] = msgin->get_uint32();
break;
default:
ERR_PRINT("[BitSet::read_serial] Unknown version: " + itos(current_version));
throw "Unknown version";
break;
}
}
String BitSet::show()
{
Ref<BitStream> msgout;
msgout.instance();
this->write_serial(msgout);
return msgout->show();
}