Files
tp-modelisation-problemes/src/ProductionOrder.cpp
2025-09-26 11:02:27 +02:00

218 lines
7.2 KiB
C++

/**
* @file ProductionOrder.cpp
* @author The ARTIS Development Team
* See the AUTHORS or Authors.txt file
*/
/*
* ARTIS - the multimodeling and simulation environment
* This file is a part of the ARTIS environment
*
* Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
*
* 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/>.
*/
#include "ProductionOrder.hpp"
#include <algorithm>
#include <cassert>
#include <cstring>
#include <memory>
namespace artis::factory {
void put_bits(uint8_t *buffer, ProductionOrder::Reference &reference, uint8_t data, uint8_t bit_number) {
if (8 - reference._bit_index >= bit_number) {
buffer[reference._byte_index] |= data << (8 - bit_number - reference._bit_index);
reference._bit_index += bit_number;
if (reference._bit_index == 8) {
++reference._byte_index;
reference._bit_index = 0;
}
} else {
buffer[reference._byte_index] |= data >> (bit_number - (8 - reference._bit_index));
++reference._byte_index;
reference._bit_index = bit_number - (8 - reference._bit_index);
data &= 0xFF >> (8 - reference._bit_index);
buffer[reference._byte_index] |= data << (8 - reference._bit_index);
}
}
uint8_t get_bits(uint8_t const *buffer,
const ProductionOrder::Reference &reference,
uint8_t bit_number) {
uint8_t data = 0;
if (8 - reference._bit_index >= bit_number) {
data = (uint8_t) (buffer[reference._byte_index] << reference._bit_index) >>
(8 - bit_number);
} else {
uint8_t mask = ~(uint8_t) (0xFF << (8 - reference._bit_index));
data = (uint8_t) (buffer[reference._byte_index] & mask);
data <<= bit_number - (8 - reference._bit_index);
data |= (uint8_t) (buffer[reference._byte_index + 1] >>
(8 - (bit_number - (8 - reference._bit_index))));
}
return data;
}
void ProductionOrder::Reference::operator+=(uint8_t p) {
_byte_index += (_bit_index + p) / 8;
_bit_index += p;
_bit_index %= 8;
}
ProductionOrder::ProductionOrder(uint8_t *buffer, std::size_t size)
: _buffer(nullptr), _size(size), _bsize(0), _current_operation(nullptr) {
_buffer = new uint8_t[size];
std::memcpy(_buffer, buffer, size);
_bsize = (_buffer[BIT_NUMBER_POSITION] << 8) + _buffer[BIT_NUMBER_POSITION + 1];
update_operation(_buffer[INDEX_POSITION]);
_is_finish = _buffer[INDEX_POSITION] + 1 >= _buffer[OPERATION_NUMBER_POSITION];
}
ProductionOrder::ProductionOrder(uint16_t ID, uint16_t product_ID, const Program &program) : _is_finish(false) {
Reference reference{0, 0};
std::size_t operation_number = 0;
_bsize = HEADER_SIZE * 8; // size + index + operation number
std::for_each(program.cbegin(), program.cend(),
[this, &operation_number](const PoolMachineSequence &sequence) {
_bsize +=
sequence._machines.size() * (MACHINE_SIZE + TYPE_SIZE);
_bsize += POOL_SIZE + TYPE_SIZE;
operation_number += sequence._machines.size() + 1;
});
_size = _bsize / 8 + 1;
_buffer = new uint8_t[_size];
memset(_buffer, 0, _size);
// bit number
_buffer[reference._byte_index++] = (uint8_t) (_bsize >> 8);
_buffer[reference._byte_index++] = (uint8_t) (_bsize & 0xFF);
// ID
_buffer[reference._byte_index++] = (uint8_t) (ID >> 8);
_buffer[reference._byte_index++] = (uint8_t) (ID & 0xFF);
// product ID
_buffer[reference._byte_index++] = (uint8_t) (product_ID >> 8);
_buffer[reference._byte_index++] = (uint8_t) (product_ID & 0xFF);
// index
_buffer[reference._byte_index++] = (uint8_t) (0);
assert(operation_number < 256);
// operation number
_buffer[reference._byte_index++] = (int8_t) (operation_number);
// operations {change pool ; N change machine} * M
std::for_each(program.cbegin(), program.cend(), [this, &reference](const PoolMachineSequence &sequence) {
const ChangePool &operation = sequence._pool;
assert(operation._pool_id < (1 << POOL_SIZE));
put_bits(_buffer, reference, CHANGE_POOL_TYPE, TYPE_SIZE);
put_bits(_buffer, reference, operation._pool_id, POOL_SIZE);
std::for_each(sequence._machines.cbegin(), sequence._machines.cend(),
[this, &reference](const ChangeMachine &operation) {
assert(operation._machine_id < (1 << MACHINE_SIZE));
put_bits(_buffer, reference, CHANGE_MACHINE_TYPE, TYPE_SIZE);
put_bits(_buffer, reference, operation._machine_id, MACHINE_SIZE);
});
});
// current operation
_current_operation = std::make_unique<ChangePool>(program.begin()->_pool);
}
std::unique_ptr<Operation> ProductionOrder::get_operation(uint8_t index) const {
Reference reference{HEADER_SIZE, 0};
uint8_t operation_type = get_bits(_buffer, reference, TYPE_SIZE);
reference += TYPE_SIZE;
while (index > 0) {
switch (operation_type) {
case CHANGE_POOL_TYPE: {
reference += POOL_SIZE;
break;
}
case CHANGE_MACHINE_TYPE: {
reference += MACHINE_SIZE;
break;
}
default:
assert(false);
}
operation_type = get_bits(_buffer, reference, TYPE_SIZE);
reference += TYPE_SIZE;
--index;
}
switch (operation_type) {
case CHANGE_POOL_TYPE: {
return std::make_unique<ChangePool>(get_bits(_buffer, reference, POOL_SIZE));
}
case CHANGE_MACHINE_TYPE: {
return std::make_unique<ChangeMachine>(get_bits(_buffer, reference, MACHINE_SIZE));
}
}
assert(false);
return {};
}
std::unique_ptr<Operation> ProductionOrder::last_operation() const {
return get_operation(operation_number() - 1);
}
void ProductionOrder::update_operation(uint8_t index) {
_current_operation = get_operation(index);
}
void ProductionOrder::next() {
if (_buffer[INDEX_POSITION] + 1 < _buffer[OPERATION_NUMBER_POSITION]) {
update_operation(++_buffer[INDEX_POSITION]);
} else {
_current_operation.reset(nullptr);
_is_finish = true;
}
}
std::unique_ptr<Operation> ProductionOrder::previous_operation() const {
return get_operation(_buffer[INDEX_POSITION] - 1);
}
std::string ProductionOrder::to_string() const {
std::string str = "[ ";
uint16_t ID = (_buffer[ID_POSITION] << 8) + _buffer[ID_POSITION + 1];
str += std::to_string(ID) + " ][ ";
for (uint8_t i = 0; i < _buffer[OPERATION_NUMBER_POSITION]; ++i) {
if (_buffer[INDEX_POSITION] == i) {
str += "<";
}
str += get_operation(i)->to_string();
if (_buffer[INDEX_POSITION] == i) {
str += ">";
}
str += " ";
}
str += "]";
return str;
}
} // namespace artis::factory