Skip to content

Instantly share code, notes, and snippets.

@laverdet
Created November 29, 2018 01:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laverdet/4df73535c8c11034ae3909fb00671fe5 to your computer and use it in GitHub Desktop.
Save laverdet/4df73535c8c11034ae3909fb00671fe5 to your computer and use it in GitHub Desktop.
screeps local matrix
// Matrix of any type which holds a value for each position in a room
template <typename Type, typename Store, size_t Pack, bool Packed = sizeof(Store) << 3 != Pack>
class local_matrix_store_t {};
template <typename Type, typename Store, size_t Pack>
class local_matrix_store_t<Type, Store, Pack, false> {
protected:
std::array<Store, 2500> costs;
using reference = Type&;
using const_reference = typename std::conditional<std::is_trivial<Type>::value && sizeof(Type) <= sizeof(size_t), Type, const Type&>::type;
public:
constexpr local_matrix_store_t() = default;
constexpr local_matrix_store_t(Type value) {
fill(value);
}
constexpr void fill(Type value) {
std::fill(costs.begin(), costs.end(), value);
}
constexpr reference operator[](int index) {
return costs[index];
}
constexpr const_reference operator[](int index) const {
return costs[index];
}
constexpr Store* data() {
return costs.data();
}
constexpr const Store* data() const {
return costs.data();
}
};
// Backing store for local_matrix_t which can bitpack 1, 2, or 4 bits into a matrix
template <typename Type, typename Store, size_t Pack>
class local_matrix_store_t<Type, Store, Pack, true> {
protected:
static constexpr uint8_t log2(size_t value) {
return value == 1 ? 0 : (1 + log2(value >> 1));
}
static constexpr uint8_t StoreBits = sizeof(Store) << 3;
static constexpr uint8_t IndexShift = log2(StoreBits / Pack);
static constexpr uint8_t IndexMask = StoreBits / Pack - 1;
static constexpr uint8_t IndexBitShift = log2(Pack);
static constexpr Store Mask = (1 << Pack) - 1;
static_assert(StoreBits >= Pack, "sizeof(Store) must be greater than or equal to pack bits");
static_assert(StoreBits % Pack == 0, "Store is not aligned to pack bits");
std::array<Store, (2500 * Pack + StoreBits / Pack) / StoreBits> costs;
class reference {
private:
Store& ref;
int bit_pos;
public:
constexpr reference(int bit_pos, Store& ref) : ref(ref), bit_pos(bit_pos) {}
constexpr operator Type() const {
return (ref >> bit_pos) & Mask;
}
constexpr const reference& operator=(Type value) const {
ref = (ref & ~(Mask << bit_pos)) | ((value & Mask) << bit_pos);
return *this;
}
};
using const_reference = Type;
public:
constexpr local_matrix_store_t() {
// Explicitly assign final data entry because otherwise it could be anything and .data() would
// be inconsistent
costs.back() = 0;
}
constexpr local_matrix_store_t(Type value) {
costs.back() = 0;
fill(value);
}
constexpr void fill(Type value) {
Store packed{};
for (int ii = 0; ii < StoreBits; ii += Pack) {
packed <<= Pack;
packed |= value & Mask;
}
costs.fill(packed);
}
constexpr reference operator[](int index) {
return {(index & IndexMask) << IndexBitShift, costs[index >> IndexShift]};
}
constexpr const_reference operator[](int index) const {
return (costs[index >> IndexShift] >> ((index & IndexMask) << IndexBitShift)) & Mask;
}
constexpr Store* data() {
return costs.data();
}
constexpr const Store* data() const {
return costs.data();
}
};
// Extra methods on top of the backing store which accept local_position_t or xx/yy coords
template <
typename Type,
typename Store = typename std::conditional<std::is_same<Type, bool>::value, uint32_t, Type>::type,
size_t Pack = std::conditional<
std::is_same<Type, bool>::value,
std::integral_constant<size_t, 1>,
std::integral_constant<size_t, sizeof(Store) << 3>
>::type::value
>
class local_matrix_t : public local_matrix_store_t<Type, Store, Pack> {
public:
using local_matrix_store_t<Type, Store, Pack>::local_matrix_store_t;
using local_matrix_store_t<Type, Store, Pack>::operator[];
using reference = typename local_matrix_store_t<Type, Store, Pack>::reference;
using const_reference = typename local_matrix_store_t<Type, Store, Pack>::const_reference;
constexpr reference get(int xx, int yy) {
return (*this)[xx * 50 + yy];
}
constexpr const_reference get(int xx, int yy) const {
return (*this)[xx * 50 + yy];
}
constexpr void set(int xx, int yy, Type cost) {
(*this)[xx * 50 + yy] = cost;
}
constexpr reference operator[](local_position_t pos) {
return get(pos.xx, pos.yy);
}
constexpr const_reference operator[](local_position_t pos) const {
return get(pos.xx, pos.yy);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment