Initialize with OpenTTD 1.9.3
This commit is contained in:
32
src/core/alloc_func.cpp
Normal file
32
src/core/alloc_func.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file alloc_func.cpp Functions to 'handle' memory allocation errors */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Function to exit with an error message after malloc() or calloc() have failed
|
||||
* @param size number of bytes we tried to allocate
|
||||
*/
|
||||
void NORETURN MallocError(size_t size)
|
||||
{
|
||||
error("Out of memory. Cannot allocate " PRINTF_SIZE " bytes", size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to exit with an error message after realloc() have failed
|
||||
* @param size number of bytes we tried to allocate
|
||||
*/
|
||||
void NORETURN ReallocError(size_t size)
|
||||
{
|
||||
error("Out of memory. Cannot reallocate " PRINTF_SIZE " bytes", size);
|
||||
}
|
||||
138
src/core/alloc_func.hpp
Normal file
138
src/core/alloc_func.hpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file alloc_func.hpp Functions related to the allocation of memory */
|
||||
|
||||
#ifndef ALLOC_FUNC_HPP
|
||||
#define ALLOC_FUNC_HPP
|
||||
|
||||
/*
|
||||
* Functions to exit badly with an error message.
|
||||
* It has to be linked so the error messages are not
|
||||
* duplicated in each object file making the final
|
||||
* binary needlessly large.
|
||||
*/
|
||||
|
||||
void NORETURN MallocError(size_t size);
|
||||
void NORETURN ReallocError(size_t size);
|
||||
|
||||
/**
|
||||
* Checks whether allocating memory would overflow size_t.
|
||||
*
|
||||
* @param element_size Size of the structure to allocate.
|
||||
* @param num_elements Number of elements to allocate.
|
||||
*/
|
||||
static inline void CheckAllocationConstraints(size_t element_size, size_t num_elements)
|
||||
{
|
||||
if (num_elements > SIZE_MAX / element_size) MallocError(SIZE_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether allocating memory would overflow size_t.
|
||||
*
|
||||
* @tparam T Structure to allocate.
|
||||
* @param num_elements Number of elements to allocate.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void CheckAllocationConstraints(size_t num_elements)
|
||||
{
|
||||
CheckAllocationConstraints(sizeof(T), num_elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified allocation function that allocates the specified number of
|
||||
* elements of the given type. It also explicitly casts it to the requested
|
||||
* type.
|
||||
* @note throws an error when there is no memory anymore.
|
||||
* @note the memory contains garbage data (i.e. possibly non-zero values).
|
||||
* @tparam T the type of the variable(s) to allocation.
|
||||
* @param num_elements the number of elements to allocate of the given type.
|
||||
* @return NULL when num_elements == 0, non-NULL otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *MallocT(size_t num_elements)
|
||||
{
|
||||
/*
|
||||
* MorphOS cannot handle 0 elements allocations, or rather that always
|
||||
* returns NULL. So we do that for *all* allocations, thus causing it
|
||||
* to behave the same on all OSes.
|
||||
*/
|
||||
if (num_elements == 0) return NULL;
|
||||
|
||||
/* Ensure the size does not overflow. */
|
||||
CheckAllocationConstraints<T>(num_elements);
|
||||
|
||||
T *t_ptr = (T*)malloc(num_elements * sizeof(T));
|
||||
if (t_ptr == NULL) MallocError(num_elements * sizeof(T));
|
||||
return t_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified allocation function that allocates the specified number of
|
||||
* elements of the given type. It also explicitly casts it to the requested
|
||||
* type.
|
||||
* @note throws an error when there is no memory anymore.
|
||||
* @note the memory contains all zero values.
|
||||
* @tparam T the type of the variable(s) to allocation.
|
||||
* @param num_elements the number of elements to allocate of the given type.
|
||||
* @return NULL when num_elements == 0, non-NULL otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *CallocT(size_t num_elements)
|
||||
{
|
||||
/*
|
||||
* MorphOS cannot handle 0 elements allocations, or rather that always
|
||||
* returns NULL. So we do that for *all* allocations, thus causing it
|
||||
* to behave the same on all OSes.
|
||||
*/
|
||||
if (num_elements == 0) return NULL;
|
||||
|
||||
T *t_ptr = (T*)calloc(num_elements, sizeof(T));
|
||||
if (t_ptr == NULL) MallocError(num_elements * sizeof(T));
|
||||
return t_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified reallocation function that allocates the specified number of
|
||||
* elements of the given type. It also explicitly casts it to the requested
|
||||
* type. It extends/shrinks the memory allocation given in t_ptr.
|
||||
* @note throws an error when there is no memory anymore.
|
||||
* @note the pointer to the data may change, but the data will remain valid.
|
||||
* @tparam T the type of the variable(s) to allocation.
|
||||
* @param t_ptr the previous allocation to extend/shrink.
|
||||
* @param num_elements the number of elements to allocate of the given type.
|
||||
* @return NULL when num_elements == 0, non-NULL otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *ReallocT(T *t_ptr, size_t num_elements)
|
||||
{
|
||||
/*
|
||||
* MorphOS cannot handle 0 elements allocations, or rather that always
|
||||
* returns NULL. So we do that for *all* allocations, thus causing it
|
||||
* to behave the same on all OSes.
|
||||
*/
|
||||
if (num_elements == 0) {
|
||||
free(t_ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure the size does not overflow. */
|
||||
CheckAllocationConstraints<T>(num_elements);
|
||||
|
||||
t_ptr = (T*)realloc(static_cast<void *>(t_ptr), num_elements * sizeof(T));
|
||||
if (t_ptr == NULL) ReallocError(num_elements * sizeof(T));
|
||||
return t_ptr;
|
||||
}
|
||||
|
||||
/** alloca() has to be called in the parent function, so define AllocaM() as a macro */
|
||||
#define AllocaM(T, num_elements) \
|
||||
(CheckAllocationConstraints<T>(num_elements), \
|
||||
(T*)alloca((num_elements) * sizeof(T)))
|
||||
|
||||
#endif /* ALLOC_FUNC_HPP */
|
||||
217
src/core/alloc_type.hpp
Normal file
217
src/core/alloc_type.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file alloc_type.hpp Helper types related to the allocation of memory */
|
||||
|
||||
#ifndef ALLOC_TYPE_HPP
|
||||
#define ALLOC_TYPE_HPP
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
|
||||
/**
|
||||
* A small 'wrapper' for allocations that can be done on most OSes on the
|
||||
* stack, but are just too large to fit in the stack on devices with a small
|
||||
* stack such as the NDS.
|
||||
* So when it is possible a stack allocation is made, otherwise a heap
|
||||
* allocation is made and this is freed once the struct goes out of scope.
|
||||
* @param T the type to make the allocation for
|
||||
* @param length the amount of items to allocate
|
||||
*/
|
||||
template <typename T, size_t length>
|
||||
struct SmallStackSafeStackAlloc {
|
||||
#if !defined(__NDS__)
|
||||
/** Storing the data on the stack */
|
||||
T data[length];
|
||||
#else
|
||||
/** Storing it on the heap */
|
||||
T *data;
|
||||
/** The length (in elements) of data in this allocator. */
|
||||
size_t len;
|
||||
|
||||
/** Allocating the memory */
|
||||
SmallStackSafeStackAlloc() : data(MallocT<T>(length)), len(length) {}
|
||||
|
||||
/** And freeing when it goes out of scope */
|
||||
~SmallStackSafeStackAlloc()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets a pointer to the data stored in this wrapper.
|
||||
* @return the pointer.
|
||||
*/
|
||||
inline operator T *()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the data stored in this wrapper.
|
||||
* @return the pointer.
|
||||
*/
|
||||
inline T *operator -> ()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the last data element stored in this wrapper.
|
||||
* @note needed because endof does not work properly for pointers.
|
||||
* @return the 'endof' pointer.
|
||||
*/
|
||||
inline T *EndOf()
|
||||
{
|
||||
#if !defined(__NDS__)
|
||||
return endof(data);
|
||||
#else
|
||||
return &data[len];
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A reusable buffer that can be used for places that temporary allocate
|
||||
* a bit of memory and do that very often, or for places where static
|
||||
* memory is allocated that might need to be reallocated sometimes.
|
||||
*
|
||||
* Every time Allocate or ZeroAllocate is called previous results of both
|
||||
* functions will become invalid.
|
||||
*/
|
||||
template <typename T>
|
||||
class ReusableBuffer {
|
||||
private:
|
||||
T *buffer; ///< The real data buffer
|
||||
size_t count; ///< Number of T elements in the buffer
|
||||
|
||||
public:
|
||||
/** Create a new buffer */
|
||||
ReusableBuffer() : buffer(NULL), count(0) {}
|
||||
/** Clear the buffer */
|
||||
~ReusableBuffer() { free(this->buffer); }
|
||||
|
||||
/**
|
||||
* Get buffer of at least count times T.
|
||||
* @note the buffer might be bigger
|
||||
* @note calling this function invalidates any previous buffers given
|
||||
* @param count the minimum buffer size
|
||||
* @return the buffer
|
||||
*/
|
||||
T *Allocate(size_t count)
|
||||
{
|
||||
if (this->count < count) {
|
||||
free(this->buffer);
|
||||
this->buffer = MallocT<T>(count);
|
||||
this->count = count;
|
||||
}
|
||||
return this->buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get buffer of at least count times T with zeroed memory.
|
||||
* @note the buffer might be bigger
|
||||
* @note calling this function invalidates any previous buffers given
|
||||
* @param count the minimum buffer size
|
||||
* @return the buffer
|
||||
*/
|
||||
T *ZeroAllocate(size_t count)
|
||||
{
|
||||
if (this->count < count) {
|
||||
free(this->buffer);
|
||||
this->buffer = CallocT<T>(count);
|
||||
this->count = count;
|
||||
} else {
|
||||
memset(this->buffer, 0, sizeof(T) * count);
|
||||
}
|
||||
return this->buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently allocated buffer.
|
||||
* @return the buffer
|
||||
*/
|
||||
inline const T *GetBuffer() const
|
||||
{
|
||||
return this->buffer;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class that provides memory initialization on dynamically created objects.
|
||||
* All allocated memory will be zeroed.
|
||||
*/
|
||||
class ZeroedMemoryAllocator
|
||||
{
|
||||
public:
|
||||
ZeroedMemoryAllocator() {}
|
||||
virtual ~ZeroedMemoryAllocator() {}
|
||||
|
||||
/**
|
||||
* Memory allocator for a single class instance.
|
||||
* @param size the amount of bytes to allocate.
|
||||
* @return the given amounts of bytes zeroed.
|
||||
*/
|
||||
inline void *operator new(size_t size) { return CallocT<byte>(size); }
|
||||
|
||||
/**
|
||||
* Memory allocator for an array of class instances.
|
||||
* @param size the amount of bytes to allocate.
|
||||
* @return the given amounts of bytes zeroed.
|
||||
*/
|
||||
inline void *operator new[](size_t size) { return CallocT<byte>(size); }
|
||||
|
||||
/**
|
||||
* Memory release for a single class instance.
|
||||
* @param ptr the memory to free.
|
||||
*/
|
||||
inline void operator delete(void *ptr) { free(ptr); }
|
||||
|
||||
/**
|
||||
* Memory release for an array of class instances.
|
||||
* @param ptr the memory to free.
|
||||
*/
|
||||
inline void operator delete[](void *ptr) { free(ptr); }
|
||||
};
|
||||
|
||||
/**
|
||||
* A smart pointer class that free()'s the pointer on destruction.
|
||||
* @tparam T Storage type.
|
||||
*/
|
||||
template <typename T>
|
||||
class AutoFreePtr
|
||||
{
|
||||
T *ptr; ///< Stored pointer.
|
||||
|
||||
public:
|
||||
AutoFreePtr(T *ptr) : ptr(ptr) {}
|
||||
~AutoFreePtr() { free(this->ptr); }
|
||||
|
||||
/**
|
||||
* Take ownership of a new pointer and free the old one if needed.
|
||||
* @param ptr NEw pointer.
|
||||
*/
|
||||
inline void Assign(T *ptr)
|
||||
{
|
||||
free(this->ptr);
|
||||
this->ptr = ptr;
|
||||
}
|
||||
|
||||
/** Dereference pointer. */
|
||||
inline T *operator ->() { return this->ptr; }
|
||||
/** Dereference pointer. */
|
||||
inline const T *operator ->() const { return this->ptr; }
|
||||
|
||||
/** Cast to underlaying regular pointer. */
|
||||
inline operator T *() { return this->ptr; }
|
||||
/** Cast to underlaying regular pointer. */
|
||||
inline operator const T *() const { return this->ptr; }
|
||||
};
|
||||
|
||||
#endif /* ALLOC_TYPE_HPP */
|
||||
149
src/core/backup_type.hpp
Normal file
149
src/core/backup_type.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file backup_type.hpp Class for backupping variables and making sure they are restored later. */
|
||||
|
||||
#ifndef BACKUP_TYPE_HPP
|
||||
#define BACKUP_TYPE_HPP
|
||||
|
||||
#include "../debug.h"
|
||||
|
||||
/**
|
||||
* Class to backup a specific variable and restore it later.
|
||||
* The variable is not restored automatically, but assertions make sure it is restored.
|
||||
* You have to call either Trash() or Restore() exactly once.
|
||||
*/
|
||||
template <typename T>
|
||||
struct Backup {
|
||||
/**
|
||||
* Backup variable.
|
||||
* @param original Variable to backup.
|
||||
* @param file Filename for debug output. Use FILE_LINE macro.
|
||||
* @param line Linenumber for debug output. Use FILE_LINE macro.
|
||||
*/
|
||||
Backup(T &original, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line) {}
|
||||
|
||||
/**
|
||||
* Backup variable and switch to new value.
|
||||
* @param original Variable to backup.
|
||||
* @param new_value New value for variable.
|
||||
* @param file Filename for debug output. Use FILE_LINE macro.
|
||||
* @param line Linenumber for debug output. Use FILE_LINE macro.
|
||||
*/
|
||||
template <typename U>
|
||||
Backup(T &original, const U &new_value, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line)
|
||||
{
|
||||
/* Note: We use a separate typename U, so type conversions are handled by assignment operator. */
|
||||
original = new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the variable was restored on object destruction.
|
||||
*/
|
||||
~Backup()
|
||||
{
|
||||
/* Check whether restoration was done */
|
||||
if (this->valid)
|
||||
{
|
||||
/* We cannot assert here, as missing restoration is 'normal' when exceptions are thrown.
|
||||
* Exceptions are especially used to abort world generation. */
|
||||
DEBUG(misc, 0, "%s:%d: Backed-up value was not restored!", this->file, this->line);
|
||||
this->Restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the variable was already restored.
|
||||
* @return true if variable has already been restored.
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
return this->valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the backupped value.
|
||||
* @return value from the backup.
|
||||
*/
|
||||
const T &GetOriginalValue() const
|
||||
{
|
||||
assert(this->valid);
|
||||
return original_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the value of the variable.
|
||||
* While this does not touch the backup at all, it ensures that the variable is only modified while backupped.
|
||||
* @param new_value New value for variable.
|
||||
*/
|
||||
template <typename U>
|
||||
void Change(const U &new_value)
|
||||
{
|
||||
/* Note: We use a separate typename U, so type conversions are handled by assignment operator. */
|
||||
assert(this->valid);
|
||||
original = new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert the variable to its original value, but do not mark it as restored.
|
||||
*/
|
||||
void Revert()
|
||||
{
|
||||
assert(this->valid);
|
||||
this->original = this->original_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trash the backup. The variable shall not be restored anymore.
|
||||
*/
|
||||
void Trash()
|
||||
{
|
||||
assert(this->valid);
|
||||
this->valid = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the variable.
|
||||
*/
|
||||
void Restore()
|
||||
{
|
||||
this->Revert();
|
||||
this->Trash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the backup.
|
||||
* That is trash the old value and make the current value of the variable the value to be restored later.
|
||||
*/
|
||||
void Update()
|
||||
{
|
||||
assert(this->valid);
|
||||
this->original_value = this->original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the variable is currently equals the backup.
|
||||
* @return true if equal
|
||||
*/
|
||||
bool Verify() const
|
||||
{
|
||||
assert(this->valid);
|
||||
return this->original_value == this->original;
|
||||
}
|
||||
|
||||
private:
|
||||
T &original;
|
||||
bool valid;
|
||||
T original_value;
|
||||
|
||||
const char * const file;
|
||||
const int line;
|
||||
};
|
||||
|
||||
#endif /* BACKUP_TYPE_HPP */
|
||||
81
src/core/bitmath_func.cpp
Normal file
81
src/core/bitmath_func.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file bitmath_func.cpp Functions related to bit mathematics. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "bitmath_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
const uint8 _ffb_64[64] = {
|
||||
0, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
5, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Search the first set bit in a 32 bit variable.
|
||||
*
|
||||
* This algorithm is a static implementation of a log
|
||||
* congruence search algorithm. It checks the first half
|
||||
* if there is a bit set search there further. And this
|
||||
* way further. If no bit is set return 0.
|
||||
*
|
||||
* @param x The value to search
|
||||
* @return The position of the first bit set
|
||||
*/
|
||||
uint8 FindFirstBit(uint32 x)
|
||||
{
|
||||
if (x == 0) return 0;
|
||||
/* The macro FIND_FIRST_BIT is better to use when your x is
|
||||
not more than 128. */
|
||||
|
||||
uint8 pos = 0;
|
||||
|
||||
if ((x & 0x0000ffff) == 0) { x >>= 16; pos += 16; }
|
||||
if ((x & 0x000000ff) == 0) { x >>= 8; pos += 8; }
|
||||
if ((x & 0x0000000f) == 0) { x >>= 4; pos += 4; }
|
||||
if ((x & 0x00000003) == 0) { x >>= 2; pos += 2; }
|
||||
if ((x & 0x00000001) == 0) { pos += 1; }
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the last set bit in a 64 bit variable.
|
||||
*
|
||||
* This algorithm is a static implementation of a log
|
||||
* congruence search algorithm. It checks the second half
|
||||
* if there is a bit set search there further. And this
|
||||
* way further. If no bit is set return 0.
|
||||
*
|
||||
* @param x The value to search
|
||||
* @return The position of the last bit set
|
||||
*/
|
||||
uint8 FindLastBit(uint64 x)
|
||||
{
|
||||
if (x == 0) return 0;
|
||||
|
||||
uint8 pos = 0;
|
||||
|
||||
if ((x & 0xffffffff00000000ULL) != 0) { x >>= 32; pos += 32; }
|
||||
if ((x & 0x00000000ffff0000ULL) != 0) { x >>= 16; pos += 16; }
|
||||
if ((x & 0x000000000000ff00ULL) != 0) { x >>= 8; pos += 8; }
|
||||
if ((x & 0x00000000000000f0ULL) != 0) { x >>= 4; pos += 4; }
|
||||
if ((x & 0x000000000000000cULL) != 0) { x >>= 2; pos += 2; }
|
||||
if ((x & 0x0000000000000002ULL) != 0) { pos += 1; }
|
||||
|
||||
return pos;
|
||||
}
|
||||
403
src/core/bitmath_func.hpp
Normal file
403
src/core/bitmath_func.hpp
Normal file
@@ -0,0 +1,403 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file bitmath_func.hpp Functions related to bit mathematics. */
|
||||
|
||||
#ifndef BITMATH_FUNC_HPP
|
||||
#define BITMATH_FUNC_HPP
|
||||
|
||||
/**
|
||||
* Fetch \a n bits from \a x, started at bit \a s.
|
||||
*
|
||||
* This function can be used to fetch \a n bits from the value \a x. The
|
||||
* \a s value set the start position to read. The start position is
|
||||
* count from the LSB and starts at \c 0. The result starts at a
|
||||
* LSB, as this isn't just an and-bitmask but also some
|
||||
* bit-shifting operations. GB(0xFF, 2, 1) will so
|
||||
* return 0x01 (0000 0001) instead of
|
||||
* 0x04 (0000 0100).
|
||||
*
|
||||
* @param x The value to read some bits.
|
||||
* @param s The start position to read some bits.
|
||||
* @param n The number of bits to read.
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @pre s + n <= sizeof(T) * 8
|
||||
* @return The selected bits, aligned to a LSB.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline uint GB(const T x, const uint8 s, const uint8 n)
|
||||
{
|
||||
return (x >> s) & (((T)1U << n) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set \a n bits in \a x starting at bit \a s to \a d
|
||||
*
|
||||
* This function sets \a n bits from \a x which started as bit \a s to the value of
|
||||
* \a d. The parameters \a x, \a s and \a n works the same as the parameters of
|
||||
* #GB. The result is saved in \a x again. Unused bits in the window
|
||||
* provided by n are set to 0 if the value of \a d isn't "big" enough.
|
||||
* This is not a bug, its a feature.
|
||||
*
|
||||
* @note Parameter \a x must be a variable as the result is saved there.
|
||||
* @note To avoid unexpected results the value of \a d should not use more
|
||||
* space as the provided space of \a n bits (log2)
|
||||
* @param x The variable to change some bits
|
||||
* @param s The start position for the new bits
|
||||
* @param n The size/window for the new bits
|
||||
* @param d The actually new bits to save in the defined position.
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @pre s + n <= sizeof(T) * 8
|
||||
* @return The new value of \a x
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
static inline T SB(T &x, const uint8 s, const uint8 n, const U d)
|
||||
{
|
||||
x &= (T)(~((((T)1U << n) - 1) << s));
|
||||
x |= (T)(d << s);
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add \a i to \a n bits of \a x starting at bit \a s.
|
||||
*
|
||||
* This adds the value of \a i on \a n bits of \a x starting at bit \a s. The parameters \a x,
|
||||
* \a s, \a i are similar to #GB. Besides, \ a x must be a variable as the result are
|
||||
* saved there. An overflow does not affect the following bits of the given
|
||||
* bit window and is simply ignored.
|
||||
*
|
||||
* @note Parameter x must be a variable as the result is saved there.
|
||||
* @param x The variable to add some bits at some position
|
||||
* @param s The start position of the addition
|
||||
* @param n The size/window for the addition
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @pre s + n <= sizeof(T) * 8
|
||||
* @param i The value to add at the given start position in the given window.
|
||||
* @return The new value of \a x
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
static inline T AB(T &x, const uint8 s, const uint8 n, const U i)
|
||||
{
|
||||
const T mask = ((((T)1U << n) - 1) << s);
|
||||
x = (T)((x & ~mask) | ((x + (i << s)) & mask));
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a bit in a value is set.
|
||||
*
|
||||
* This function checks if a bit inside a value is set or not.
|
||||
* The \a y value specific the position of the bit, started at the
|
||||
* LSB and count from \c 0.
|
||||
*
|
||||
* @param x The value to check
|
||||
* @param y The position of the bit to check, started from the LSB
|
||||
* @pre y < sizeof(T) * 8
|
||||
* @return True if the bit is set, false else.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool HasBit(const T x, const uint8 y)
|
||||
{
|
||||
return (x & ((T)1U << y)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bit in a variable.
|
||||
*
|
||||
* This function sets a bit in a variable. The variable is changed
|
||||
* and the value is also returned. Parameter y defines the bit and
|
||||
* starts at the LSB with 0.
|
||||
*
|
||||
* @param x The variable to set a bit
|
||||
* @param y The bit position to set
|
||||
* @pre y < sizeof(T) * 8
|
||||
* @return The new value of the old value with the bit set
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T SetBit(T &x, const uint8 y)
|
||||
{
|
||||
return x = (T)(x | ((T)1U << y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets several bits in a variable.
|
||||
*
|
||||
* This macro sets several bits in a variable. The bits to set are provided
|
||||
* by a value. The new value is also returned.
|
||||
*
|
||||
* @param x The variable to set some bits
|
||||
* @param y The value with set bits for setting them in the variable
|
||||
* @return The new value of x
|
||||
*/
|
||||
#define SETBITS(x, y) ((x) |= (y))
|
||||
|
||||
/**
|
||||
* Clears a bit in a variable.
|
||||
*
|
||||
* This function clears a bit in a variable. The variable is
|
||||
* changed and the value is also returned. Parameter y defines the bit
|
||||
* to clear and starts at the LSB with 0.
|
||||
*
|
||||
* @param x The variable to clear the bit
|
||||
* @param y The bit position to clear
|
||||
* @pre y < sizeof(T) * 8
|
||||
* @return The new value of the old value with the bit cleared
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ClrBit(T &x, const uint8 y)
|
||||
{
|
||||
return x = (T)(x & ~((T)1U << y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears several bits in a variable.
|
||||
*
|
||||
* This macro clears several bits in a variable. The bits to clear are
|
||||
* provided by a value. The new value is also returned.
|
||||
*
|
||||
* @param x The variable to clear some bits
|
||||
* @param y The value with set bits for clearing them in the variable
|
||||
* @return The new value of x
|
||||
*/
|
||||
#define CLRBITS(x, y) ((x) &= ~(y))
|
||||
|
||||
/**
|
||||
* Toggles a bit in a variable.
|
||||
*
|
||||
* This function toggles a bit in a variable. The variable is
|
||||
* changed and the value is also returned. Parameter y defines the bit
|
||||
* to toggle and starts at the LSB with 0.
|
||||
*
|
||||
* @param x The variable to toggle the bit
|
||||
* @param y The bit position to toggle
|
||||
* @pre y < sizeof(T) * 8
|
||||
* @return The new value of the old value with the bit toggled
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ToggleBit(T &x, const uint8 y)
|
||||
{
|
||||
return x = (T)(x ^ ((T)1U << y));
|
||||
}
|
||||
|
||||
|
||||
/** Lookup table to check which bit is set in a 6 bit variable */
|
||||
extern const uint8 _ffb_64[64];
|
||||
|
||||
/**
|
||||
* Returns the first non-zero bit in a 6-bit value (from right).
|
||||
*
|
||||
* Returns the position of the first bit that is not zero, counted from the
|
||||
* LSB. Ie, 110100 returns 2, 000001 returns 0, etc. When x == 0 returns
|
||||
* 0.
|
||||
*
|
||||
* @param x The 6-bit value to check the first zero-bit
|
||||
* @return The first position of a bit started from the LSB or 0 if x is 0.
|
||||
*/
|
||||
#define FIND_FIRST_BIT(x) _ffb_64[(x)]
|
||||
|
||||
/**
|
||||
* Finds the position of the first non-zero bit in an integer.
|
||||
*
|
||||
* This function returns the position of the first bit set in the
|
||||
* integer. It does only check the bits of the bitmask
|
||||
* 0x3F3F (0011111100111111) and checks only the
|
||||
* bits of the bitmask 0x3F00 if and only if the
|
||||
* lower part 0x00FF is 0. This results the bits at 0x00C0 must
|
||||
* be also zero to check the bits at 0x3F00.
|
||||
*
|
||||
* @param value The value to check the first bits
|
||||
* @return The position of the first bit which is set
|
||||
* @see FIND_FIRST_BIT
|
||||
*/
|
||||
static inline uint8 FindFirstBit2x64(const int value)
|
||||
{
|
||||
if ((value & 0xFF) == 0) {
|
||||
return FIND_FIRST_BIT((value >> 8) & 0x3F) + 8;
|
||||
} else {
|
||||
return FIND_FIRST_BIT(value & 0x3F);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 FindFirstBit(uint32 x);
|
||||
uint8 FindLastBit(uint64 x);
|
||||
|
||||
/**
|
||||
* Clear the first bit in an integer.
|
||||
*
|
||||
* This function returns a value where the first bit (from LSB)
|
||||
* is cleared.
|
||||
* So, 110100 returns 110000, 000001 returns 000000, etc.
|
||||
*
|
||||
* @param value The value to clear the first bit
|
||||
* @return The new value with the first bit cleared
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T KillFirstBit(T value)
|
||||
{
|
||||
return value &= (T)(value - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of set bits in a variable.
|
||||
*
|
||||
* @param value the value to count the number of bits in.
|
||||
* @return the number of bits.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline uint CountBits(T value)
|
||||
{
|
||||
uint num;
|
||||
|
||||
/* This loop is only called once for every bit set by clearing the lowest
|
||||
* bit in each loop. The number of bits is therefore equal to the number of
|
||||
* times the loop was called. It was found at the following website:
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html */
|
||||
|
||||
for (num = 0; value != 0; num++) {
|
||||
value &= (T)(value - 1);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether \a value has exactly 1 bit set
|
||||
*
|
||||
* @param value the value to test.
|
||||
* @return does \a value have exactly 1 bit set?
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool HasExactlyOneBit(T value)
|
||||
{
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether \a value has at most 1 bit set
|
||||
*
|
||||
* @param value the value to test.
|
||||
* @return does \a value have at most 1 bit set?
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool HasAtMostOneBit(T value)
|
||||
{
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ROtate \a x Left by \a n
|
||||
*
|
||||
* @note Assumes a byte has 8 bits
|
||||
* @param x The value which we want to rotate
|
||||
* @param n The number how many we want to rotate
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @return A bit rotated number
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ROL(const T x, const uint8 n)
|
||||
{
|
||||
if (n == 0) return x;
|
||||
return (T)(x << n | x >> (sizeof(x) * 8 - n));
|
||||
}
|
||||
|
||||
/**
|
||||
* ROtate \a x Right by \a n
|
||||
*
|
||||
* @note Assumes a byte has 8 bits
|
||||
* @param x The value which we want to rotate
|
||||
* @param n The number how many we want to rotate
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @return A bit rotated number
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ROR(const T x, const uint8 n)
|
||||
{
|
||||
if (n == 0) return x;
|
||||
return (T)(x >> n | x << (sizeof(x) * 8 - n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do an operation for each set bit in a value.
|
||||
*
|
||||
* This macros is used to do an operation for each set
|
||||
* bit in a variable. The second parameter is a
|
||||
* variable that is used as the bit position counter.
|
||||
* The fourth parameter is an expression of the bits
|
||||
* we need to iterate over. This expression will be
|
||||
* evaluated once.
|
||||
*
|
||||
* @param Tbitpos_type Type of the position counter variable.
|
||||
* @param bitpos_var The position counter variable.
|
||||
* @param Tbitset_type Type of the bitset value.
|
||||
* @param bitset_value The bitset value which we check for bits.
|
||||
*
|
||||
* @see FOR_EACH_SET_BIT
|
||||
*/
|
||||
#define FOR_EACH_SET_BIT_EX(Tbitpos_type, bitpos_var, Tbitset_type, bitset_value) \
|
||||
for ( \
|
||||
Tbitset_type ___FESBE_bits = (bitpos_var = (Tbitpos_type)0, bitset_value); \
|
||||
___FESBE_bits != (Tbitset_type)0; \
|
||||
___FESBE_bits = (Tbitset_type)(___FESBE_bits >> 1), bitpos_var++ \
|
||||
) \
|
||||
if ((___FESBE_bits & 1) != 0)
|
||||
|
||||
/**
|
||||
* Do an operation for each set set bit in a value.
|
||||
*
|
||||
* This macros is used to do an operation for each set
|
||||
* bit in a variable. The first parameter is a variable
|
||||
* that is used as the bit position counter.
|
||||
* The second parameter is an expression of the bits
|
||||
* we need to iterate over. This expression will be
|
||||
* evaluated once.
|
||||
*
|
||||
* @param bitpos_var The position counter variable.
|
||||
* @param bitset_value The value which we check for set bits.
|
||||
*/
|
||||
#define FOR_EACH_SET_BIT(bitpos_var, bitset_value) FOR_EACH_SET_BIT_EX(uint, bitpos_var, uint, bitset_value)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Make endian swapping use Apple's macros to increase speed
|
||||
* (since it will use hardware swapping if available).
|
||||
* Even though they should return uint16 and uint32, we get
|
||||
* warnings if we don't cast those (why?) */
|
||||
#define BSWAP32(x) ((uint32)CFSwapInt32(x))
|
||||
#define BSWAP16(x) ((uint16)CFSwapInt16(x))
|
||||
#elif defined(_MSC_VER)
|
||||
/* MSVC has intrinsics for swapping, resulting in faster code */
|
||||
#define BSWAP32(x) (_byteswap_ulong(x))
|
||||
#define BSWAP16(x) (_byteswap_ushort(x))
|
||||
#else
|
||||
/**
|
||||
* Perform a 32 bits endianness bitswap on x.
|
||||
* @param x the variable to bitswap
|
||||
* @return the bitswapped value.
|
||||
*/
|
||||
static inline uint32 BSWAP32(uint32 x)
|
||||
{
|
||||
#if !defined(__ICC) && defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ >= 3))
|
||||
/* GCC >= 4.3 provides a builtin, resulting in faster code */
|
||||
return (uint32)__builtin_bswap32((int32)x);
|
||||
#else
|
||||
return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
|
||||
#endif /* defined(__GNUC__) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a 16 bits endianness bitswap on x.
|
||||
* @param x the variable to bitswap
|
||||
* @return the bitswapped value.
|
||||
*/
|
||||
static inline uint16 BSWAP16(uint16 x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#endif /* BITMATH_FUNC_HPP */
|
||||
57
src/core/endian_func.hpp
Normal file
57
src/core/endian_func.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file endian_func.hpp Function to handling different endian machines. */
|
||||
|
||||
#ifndef ENDIAN_FUNC_HPP
|
||||
#define ENDIAN_FUNC_HPP
|
||||
|
||||
#include "endian_type.hpp"
|
||||
#include "bitmath_func.hpp"
|
||||
|
||||
/* Setup alignment and conversion macros */
|
||||
#if TTD_ENDIAN == TTD_BIG_ENDIAN
|
||||
#define FROM_BE16(x) (x)
|
||||
#define FROM_BE32(x) (x)
|
||||
#define TO_BE16(x) (x)
|
||||
#define TO_BE32(x) (x)
|
||||
#define TO_BE32X(x) (x)
|
||||
#define FROM_LE16(x) BSWAP16(x)
|
||||
#define FROM_LE32(x) BSWAP32(x)
|
||||
#define TO_LE16(x) BSWAP16(x)
|
||||
#define TO_LE32(x) BSWAP32(x)
|
||||
#define TO_LE32X(x) BSWAP32(x)
|
||||
#else
|
||||
#define FROM_BE16(x) BSWAP16(x)
|
||||
#define FROM_BE32(x) BSWAP32(x)
|
||||
#define TO_BE16(x) BSWAP16(x)
|
||||
#define TO_BE32(x) BSWAP32(x)
|
||||
#define TO_BE32X(x) BSWAP32(x)
|
||||
#define FROM_LE16(x) (x)
|
||||
#define FROM_LE32(x) (x)
|
||||
#define TO_LE16(x) (x)
|
||||
#define TO_LE32(x) (x)
|
||||
#define TO_LE32X(x) (x)
|
||||
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
|
||||
|
||||
static inline uint16 ReadLE16Aligned(const void *x)
|
||||
{
|
||||
return FROM_LE16(*(const uint16*)x);
|
||||
}
|
||||
|
||||
static inline uint16 ReadLE16Unaligned(const void *x)
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 1
|
||||
return ((const byte*)x)[0] | ((const byte*)x)[1] << 8;
|
||||
#else
|
||||
return FROM_LE16(*(const uint16*)x);
|
||||
#endif /* OTTD_ALIGNMENT == 1 */
|
||||
}
|
||||
|
||||
#endif /* ENDIAN_FUNC_HPP */
|
||||
47
src/core/endian_type.hpp
Normal file
47
src/core/endian_type.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file endian_type.hpp Definition of various endian-dependant macros. */
|
||||
|
||||
#ifndef ENDIAN_TYPE_HPP
|
||||
#define ENDIAN_TYPE_HPP
|
||||
|
||||
#if defined(ARM) || defined(__arm__) || defined(__alpha__)
|
||||
/** The architecture requires aligned access. */
|
||||
#define OTTD_ALIGNMENT 1
|
||||
#else
|
||||
/** The architecture does not require aligned access. */
|
||||
#define OTTD_ALIGNMENT 0
|
||||
#endif
|
||||
|
||||
/** Little endian builds use this for TTD_ENDIAN. */
|
||||
#define TTD_LITTLE_ENDIAN 0
|
||||
/** Big endian builds use this for TTD_ENDIAN. */
|
||||
#define TTD_BIG_ENDIAN 1
|
||||
|
||||
/* Windows has always LITTLE_ENDIAN */
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
# define TTD_ENDIAN TTD_LITTLE_ENDIAN
|
||||
#elif defined(OSX)
|
||||
# include <sys/types.h>
|
||||
# if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
|
||||
# define TTD_ENDIAN TTD_LITTLE_ENDIAN
|
||||
# else
|
||||
# define TTD_ENDIAN TTD_BIG_ENDIAN
|
||||
# endif
|
||||
#elif !defined(TESTING)
|
||||
# include <sys/param.h>
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define TTD_ENDIAN TTD_LITTLE_ENDIAN
|
||||
# else
|
||||
# define TTD_ENDIAN TTD_BIG_ENDIAN
|
||||
# endif
|
||||
#endif /* _WIN32 || __OS2__ */
|
||||
|
||||
#endif /* ENDIAN_TYPE_HPP */
|
||||
179
src/core/enum_type.hpp
Normal file
179
src/core/enum_type.hpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file enum_type.hpp Type (helpers) for enums */
|
||||
|
||||
#ifndef ENUM_TYPE_HPP
|
||||
#define ENUM_TYPE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
/** Some enums need to have allowed incrementing (i.e. StationClassID) */
|
||||
#define DECLARE_POSTFIX_INCREMENT(enum_type) \
|
||||
inline enum_type operator ++(enum_type& e, int) \
|
||||
{ \
|
||||
enum_type e_org = e; \
|
||||
e = (enum_type)((std::underlying_type<enum_type>::type)e + 1); \
|
||||
return e_org; \
|
||||
} \
|
||||
inline enum_type operator --(enum_type& e, int) \
|
||||
{ \
|
||||
enum_type e_org = e; \
|
||||
e = (enum_type)((std::underlying_type<enum_type>::type)e - 1); \
|
||||
return e_org; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Operators to allow to work with enum as with type safe bit set in C++ */
|
||||
# define DECLARE_ENUM_AS_BIT_SET(mask_t) \
|
||||
inline mask_t operator | (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 | m2);} \
|
||||
inline mask_t operator & (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 & m2);} \
|
||||
inline mask_t operator ^ (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 ^ m2);} \
|
||||
inline mask_t& operator |= (mask_t& m1, mask_t m2) {m1 = m1 | m2; return m1;} \
|
||||
inline mask_t& operator &= (mask_t& m1, mask_t m2) {m1 = m1 & m2; return m1;} \
|
||||
inline mask_t& operator ^= (mask_t& m1, mask_t m2) {m1 = m1 ^ m2; return m1;} \
|
||||
inline mask_t operator ~(mask_t m) {return (mask_t)(~(std::underlying_type<mask_t>::type)m);}
|
||||
|
||||
|
||||
/**
|
||||
* Informative template class exposing basic enumeration properties used by several
|
||||
* other templates below. Here we have only forward declaration. For each enum type
|
||||
* we will create specialization derived from MakeEnumPropsT<>.
|
||||
* i.e.:
|
||||
* template <> struct EnumPropsT<Track> : MakeEnumPropsT<Track, byte, TRACK_BEGIN, TRACK_END, INVALID_TRACK> {};
|
||||
* followed by:
|
||||
* typedef TinyEnumT<Track> TrackByte;
|
||||
*/
|
||||
template <typename Tenum_t> struct EnumPropsT;
|
||||
|
||||
/**
|
||||
* Helper template class that makes basic properties of given enumeration type visible
|
||||
* from outsize. It is used as base class of several EnumPropsT specializations each
|
||||
* dedicated to one of commonly used enumeration types.
|
||||
* @param Tenum_t enumeration type that you want to describe
|
||||
* @param Tstorage_t what storage type would be sufficient (i.e. byte)
|
||||
* @param Tbegin first valid value from the contiguous range (i.e. TRACK_BEGIN)
|
||||
* @param Tend one past the last valid value from the contiguous range (i.e. TRACK_END)
|
||||
* @param Tinvalid value used as invalid value marker (i.e. INVALID_TRACK)
|
||||
* @param Tnum_bits Number of bits for storing the enum in command parameters
|
||||
*/
|
||||
template <typename Tenum_t, typename Tstorage_t, Tenum_t Tbegin, Tenum_t Tend, Tenum_t Tinvalid, uint Tnum_bits = 8 * sizeof(Tstorage_t)>
|
||||
struct MakeEnumPropsT {
|
||||
typedef Tenum_t type; ///< enum type (i.e. Trackdir)
|
||||
typedef Tstorage_t storage; ///< storage type (i.e. byte)
|
||||
static const Tenum_t begin = Tbegin; ///< lowest valid value (i.e. TRACKDIR_BEGIN)
|
||||
static const Tenum_t end = Tend; ///< one after the last valid value (i.e. TRACKDIR_END)
|
||||
static const Tenum_t invalid = Tinvalid; ///< what value is used as invalid value (i.e. INVALID_TRACKDIR)
|
||||
static const uint num_bits = Tnum_bits; ///< Number of bits for storing the enum in command parameters
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* In some cases we use byte or uint16 to store values that are defined as enum. It is
|
||||
* necessary in order to control the sizeof() such values. Some compilers make enum
|
||||
* the same size as int (4 or 8 bytes instead of 1 or 2). As a consequence the strict
|
||||
* compiler type - checking causes errors like:
|
||||
* 'HasPowerOnRail' : cannot convert parameter 1 from 'byte' to 'RailType' when
|
||||
* u->u.rail.railtype is passed as argument or type RailType. In such cases it is better
|
||||
* to teach the compiler that u->u.rail.railtype is to be treated as RailType.
|
||||
*/
|
||||
template <typename Tenum_t> struct TinyEnumT;
|
||||
|
||||
/** The general declaration of TinyEnumT<> (above) */
|
||||
template <typename Tenum_t>
|
||||
struct TinyEnumT {
|
||||
typedef Tenum_t enum_type; ///< expose our enumeration type (i.e. Trackdir) to outside
|
||||
typedef EnumPropsT<Tenum_t> Props; ///< make easier access to our enumeration properties
|
||||
typedef typename Props::storage storage_type; ///< small storage type
|
||||
static const enum_type begin = Props::begin; ///< enum beginning (i.e. TRACKDIR_BEGIN)
|
||||
static const enum_type end = Props::end; ///< enum end (i.e. TRACKDIR_END)
|
||||
static const enum_type invalid = Props::invalid;///< invalid value (i.e. INVALID_TRACKDIR)
|
||||
|
||||
storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form
|
||||
|
||||
/** Cast operator - invoked then the value is assigned to the Tenum_t type */
|
||||
inline operator enum_type () const
|
||||
{
|
||||
return (enum_type)m_val;
|
||||
}
|
||||
|
||||
/** Assignment operator (from Tenum_t type) */
|
||||
inline TinyEnumT& operator = (enum_type e)
|
||||
{
|
||||
m_val = (storage_type)e;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assignment operator (from Tenum_t type) */
|
||||
inline TinyEnumT& operator = (uint u)
|
||||
{
|
||||
m_val = (storage_type)u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** postfix ++ operator on tiny type */
|
||||
inline TinyEnumT operator ++ (int)
|
||||
{
|
||||
TinyEnumT org = *this;
|
||||
if (++m_val >= end) m_val -= (storage_type)(end - begin);
|
||||
return org;
|
||||
}
|
||||
|
||||
/** prefix ++ operator on tiny type */
|
||||
inline TinyEnumT& operator ++ ()
|
||||
{
|
||||
if (++m_val >= end) m_val -= (storage_type)(end - begin);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Template of struct holding enum types (on most archs, enums are stored in an int32). No math operators are provided. */
|
||||
template <typename enum_type, typename storage_type>
|
||||
struct SimpleTinyEnumT {
|
||||
storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form
|
||||
|
||||
/** Cast operator - invoked then the value is assigned to the storage_type */
|
||||
inline operator enum_type () const
|
||||
{
|
||||
return (enum_type)this->m_val;
|
||||
}
|
||||
|
||||
/** Assignment operator (from enum_type) */
|
||||
inline SimpleTinyEnumT &operator = (enum_type e)
|
||||
{
|
||||
this->m_val = (storage_type)e;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assignment operator (from general uint) */
|
||||
inline SimpleTinyEnumT &operator = (uint u)
|
||||
{
|
||||
this->m_val = (storage_type)u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Bit math (or) assignment operator (from enum_type) */
|
||||
inline SimpleTinyEnumT &operator |= (enum_type e)
|
||||
{
|
||||
this->m_val = (storage_type)((enum_type)this->m_val | e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Bit math (and) assignment operator (from enum_type) */
|
||||
inline SimpleTinyEnumT &operator &= (enum_type e)
|
||||
{
|
||||
this->m_val = (storage_type)((enum_type)this->m_val & e);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ENUM_TYPE_HPP */
|
||||
30
src/core/geometry_func.cpp
Normal file
30
src/core/geometry_func.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file geometry_func.cpp Geometry functions. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "geometry_func.hpp"
|
||||
#include "math_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Compute bounding box of both dimensions.
|
||||
* @param d1 First dimension.
|
||||
* @param d2 Second dimension.
|
||||
* @return The bounding box of both dimensions, the smallest dimension that surrounds both arguments.
|
||||
*/
|
||||
Dimension maxdim(const Dimension &d1, const Dimension &d2)
|
||||
{
|
||||
Dimension d;
|
||||
d.width = max(d1.width, d2.width);
|
||||
d.height = max(d1.height, d2.height);
|
||||
return d;
|
||||
}
|
||||
19
src/core/geometry_func.hpp
Normal file
19
src/core/geometry_func.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file geometry_func.hpp Geometry functions. */
|
||||
|
||||
#ifndef GEOMETRY_FUNC_HPP
|
||||
#define GEOMETRY_FUNC_HPP
|
||||
|
||||
#include "geometry_type.hpp"
|
||||
|
||||
Dimension maxdim(const Dimension &d1, const Dimension &d2);
|
||||
|
||||
#endif /* GEOMETRY_FUNC_HPP */
|
||||
64
src/core/geometry_type.hpp
Normal file
64
src/core/geometry_type.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file geometry_type.hpp All geometry types in OpenTTD. */
|
||||
|
||||
#ifndef GEOMETRY_TYPE_HPP
|
||||
#define GEOMETRY_TYPE_HPP
|
||||
|
||||
#if defined(__AMIGA__)
|
||||
/* AmigaOS already has a Point declared */
|
||||
#define Point OTTD_Point
|
||||
#endif /* __AMIGA__ */
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Mac OS X already has both Rect and Point declared */
|
||||
#define Rect OTTD_Rect
|
||||
#define Point OTTD_Point
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
|
||||
/** Coordinates of a point in 2D */
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
/** Dimensions (a width and height) of a rectangle in 2D */
|
||||
struct Dimension {
|
||||
uint width;
|
||||
uint height;
|
||||
};
|
||||
|
||||
/** Specification of a rectangle with absolute coordinates of all edges */
|
||||
struct Rect {
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specification of a rectangle with an absolute top-left coordinate and a
|
||||
* (relative) width/height
|
||||
*/
|
||||
struct PointDimension {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
/** A pair of two integers */
|
||||
struct Pair {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
#endif /* GEOMETRY_TYPE_HPP */
|
||||
101
src/core/math_func.cpp
Normal file
101
src/core/math_func.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file math_func.cpp Math functions. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "math_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Compute least common multiple (lcm) of arguments \a a and \a b, the smallest
|
||||
* integer value that is a multiple of both \a a and \a b.
|
||||
* @param a First number.
|
||||
* @param b second number.
|
||||
* @return Least common multiple of values \a a and \a b.
|
||||
*
|
||||
* @note This function only works for non-negative values of \a a and \a b.
|
||||
*/
|
||||
int LeastCommonMultiple(int a, int b)
|
||||
{
|
||||
if (a == 0 || b == 0) return 0; // By definition.
|
||||
if (a == 1 || a == b) return b;
|
||||
if (b == 1) return a;
|
||||
|
||||
return a * b / GreatestCommonDivisor(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute greatest common divisor (gcd) of \a a and \a b.
|
||||
* @param a First number.
|
||||
* @param b second number.
|
||||
* @return Greatest common divisor of \a a and \a b.
|
||||
*/
|
||||
int GreatestCommonDivisor(int a, int b)
|
||||
{
|
||||
while (b != 0) {
|
||||
int t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deterministic approximate division.
|
||||
* Cancels out division errors stemming from the integer nature of the division over multiple runs.
|
||||
* @param a Dividend.
|
||||
* @param b Divisor.
|
||||
* @return a/b or (a/b)+1.
|
||||
*/
|
||||
int DivideApprox(int a, int b)
|
||||
{
|
||||
int random_like = ((a + b) * (a - b)) % b;
|
||||
|
||||
int remainder = a % b;
|
||||
|
||||
int ret = a / b;
|
||||
if (abs(random_like) < abs(remainder)) {
|
||||
ret += ((a < 0) ^ (b < 0)) ? -1 : 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the integer square root.
|
||||
* @param num Radicand.
|
||||
* @return Rounded integer square root.
|
||||
* @note Algorithm taken from http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
|
||||
*/
|
||||
uint32 IntSqrt(uint32 num)
|
||||
{
|
||||
uint32 res = 0;
|
||||
uint32 bit = 1UL << 30; // Second to top bit number.
|
||||
|
||||
/* 'bit' starts at the highest power of four <= the argument. */
|
||||
while (bit > num) bit >>= 2;
|
||||
|
||||
while (bit != 0) {
|
||||
if (num >= res + bit) {
|
||||
num -= res + bit;
|
||||
res = (res >> 1) + bit;
|
||||
} else {
|
||||
res >>= 1;
|
||||
}
|
||||
bit >>= 2;
|
||||
}
|
||||
|
||||
/* Arithmetic rounding to nearest integer. */
|
||||
if (num > res) res++;
|
||||
|
||||
return res;
|
||||
}
|
||||
368
src/core/math_func.hpp
Normal file
368
src/core/math_func.hpp
Normal file
@@ -0,0 +1,368 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file math_func.hpp Integer math functions */
|
||||
|
||||
#ifndef MATH_FUNC_HPP
|
||||
#define MATH_FUNC_HPP
|
||||
|
||||
/**
|
||||
* Returns the maximum of two values.
|
||||
*
|
||||
* This function returns the greater value of two given values.
|
||||
* If they are equal the value of a is returned.
|
||||
*
|
||||
* @param a The first value
|
||||
* @param b The second value
|
||||
* @return The greater value or a if equals
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T max(const T a, const T b)
|
||||
{
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum of two values.
|
||||
*
|
||||
* This function returns the smaller value of two given values.
|
||||
* If they are equal the value of b is returned.
|
||||
*
|
||||
* @param a The first value
|
||||
* @param b The second value
|
||||
* @return The smaller value or b if equals
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T min(const T a, const T b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum of two integer.
|
||||
*
|
||||
* This function returns the smaller value of two given integers.
|
||||
*
|
||||
* @param a The first integer
|
||||
* @param b The second integer
|
||||
* @return The smaller value
|
||||
*/
|
||||
static inline int min(const int a, const int b)
|
||||
{
|
||||
return min<int>(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum of two unsigned integers.
|
||||
*
|
||||
* This function returns the smaller value of two given unsigned integers.
|
||||
*
|
||||
* @param a The first unsigned integer
|
||||
* @param b The second unsigned integer
|
||||
* @return The smaller value
|
||||
*/
|
||||
static inline uint minu(const uint a, const uint b)
|
||||
{
|
||||
return min<uint>(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value of (scalar) variable.
|
||||
*
|
||||
* @note assumes variable to be signed
|
||||
* @param a The value we want to unsign
|
||||
* @return The unsigned value
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T abs(const T a)
|
||||
{
|
||||
return (a < (T)0) ? -a : a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the smallest multiple of n equal or greater than x
|
||||
*
|
||||
* @note n must be a power of 2
|
||||
* @param x The min value
|
||||
* @param n The base of the number we are searching
|
||||
* @return The smallest multiple of n equal or greater than x
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T Align(const T x, uint n)
|
||||
{
|
||||
assert((n & (n - 1)) == 0 && n != 0);
|
||||
n--;
|
||||
return (T)((x + n) & ~((T)n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the smallest multiple of n equal or greater than x
|
||||
* Applies to pointers only
|
||||
*
|
||||
* @note n must be a power of 2
|
||||
* @param x The min value
|
||||
* @param n The base of the number we are searching
|
||||
* @return The smallest multiple of n equal or greater than x
|
||||
* @see Align()
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *AlignPtr(T *x, uint n)
|
||||
{
|
||||
assert_compile(sizeof(size_t) == sizeof(void *));
|
||||
return (T *)Align((size_t)x, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp a value between an interval.
|
||||
*
|
||||
* This function returns a value which is between the given interval of
|
||||
* min and max. If the given value is in this interval the value itself
|
||||
* is returned otherwise the border of the interval is returned, according
|
||||
* which side of the interval was 'left'.
|
||||
*
|
||||
* @note The min value must be less or equal of max or you get some
|
||||
* unexpected results.
|
||||
* @param a The value to clamp/truncate.
|
||||
* @param min The minimum of the interval.
|
||||
* @param max the maximum of the interval.
|
||||
* @returns A value between min and max which is closest to a.
|
||||
* @see ClampU(uint, uint, uint)
|
||||
* @see Clamp(int, int, int)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T Clamp(const T a, const T min, const T max)
|
||||
{
|
||||
assert(min <= max);
|
||||
if (a <= min) return min;
|
||||
if (a >= max) return max;
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp an integer between an interval.
|
||||
*
|
||||
* This function returns a value which is between the given interval of
|
||||
* min and max. If the given value is in this interval the value itself
|
||||
* is returned otherwise the border of the interval is returned, according
|
||||
* which side of the interval was 'left'.
|
||||
*
|
||||
* @note The min value must be less or equal of max or you get some
|
||||
* unexpected results.
|
||||
* @param a The value to clamp/truncate.
|
||||
* @param min The minimum of the interval.
|
||||
* @param max the maximum of the interval.
|
||||
* @returns A value between min and max which is closest to a.
|
||||
* @see ClampU(uint, uint, uint)
|
||||
*/
|
||||
static inline int Clamp(const int a, const int min, const int max)
|
||||
{
|
||||
return Clamp<int>(a, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp an unsigned integer between an interval.
|
||||
*
|
||||
* This function returns a value which is between the given interval of
|
||||
* min and max. If the given value is in this interval the value itself
|
||||
* is returned otherwise the border of the interval is returned, according
|
||||
* which side of the interval was 'left'.
|
||||
*
|
||||
* @note The min value must be less or equal of max or you get some
|
||||
* unexpected results.
|
||||
* @param a The value to clamp/truncate.
|
||||
* @param min The minimum of the interval.
|
||||
* @param max the maximum of the interval.
|
||||
* @returns A value between min and max which is closest to a.
|
||||
* @see Clamp(int, int, int)
|
||||
*/
|
||||
static inline uint ClampU(const uint a, const uint min, const uint max)
|
||||
{
|
||||
return Clamp<uint>(a, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a signed 64-bit int to a signed 32-bit one
|
||||
*
|
||||
* This function clamps a 64-bit integer to a 32-bit integer.
|
||||
* If the 64-bit value is smaller than the smallest 32-bit integer
|
||||
* value 0x80000000 this value is returned (the left one bit is the sign bit).
|
||||
* If the 64-bit value is greater than the greatest 32-bit integer value 0x7FFFFFFF
|
||||
* this value is returned. In all other cases the 64-bit value 'fits' in a
|
||||
* 32-bits integer field and so the value is casted to int32 and returned.
|
||||
*
|
||||
* @param a The 64-bit value to clamps
|
||||
* @return The 64-bit value reduced to a 32-bit value
|
||||
* @see Clamp(int, int, int)
|
||||
*/
|
||||
static inline int32 ClampToI32(const int64 a)
|
||||
{
|
||||
return (int32)Clamp<int64>(a, INT32_MIN, INT32_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce an unsigned 64-bit int to an unsigned 16-bit one
|
||||
*
|
||||
* @param a The 64-bit value to clamp
|
||||
* @return The 64-bit value reduced to a 16-bit value
|
||||
* @see ClampU(uint, uint, uint)
|
||||
*/
|
||||
static inline uint16 ClampToU16(const uint64 a)
|
||||
{
|
||||
/* MSVC thinks, in its infinite wisdom, that int min(int, int) is a better
|
||||
* match for min(uint64, uint) than uint64 min(uint64, uint64). As such we
|
||||
* need to cast the UINT16_MAX to prevent MSVC from displaying its
|
||||
* infinite loads of warnings. */
|
||||
return (uint16)min<uint64>(a, (uint64)UINT16_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (absolute) difference between two (scalar) variables
|
||||
*
|
||||
* @param a The first scalar
|
||||
* @param b The second scalar
|
||||
* @return The absolute difference between the given scalars
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T Delta(const T a, const T b)
|
||||
{
|
||||
return (a < b) ? b - a : a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is between a window started at some base point.
|
||||
*
|
||||
* This function checks if the value x is between the value of base
|
||||
* and base+size. If x equals base this returns true. If x equals
|
||||
* base+size this returns false.
|
||||
*
|
||||
* @param x The value to check
|
||||
* @param base The base value of the interval
|
||||
* @param size The size of the interval
|
||||
* @return True if the value is in the interval, false else.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool IsInsideBS(const T x, const uint base, const uint size)
|
||||
{
|
||||
return (uint)(x - base) < size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is in an interval.
|
||||
*
|
||||
* Returns true if a value is in the interval of [min, max).
|
||||
*
|
||||
* @param x The value to check
|
||||
* @param min The minimum of the interval
|
||||
* @param max The maximum of the interval
|
||||
* @see IsInsideBS()
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool IsInsideMM(const T x, const uint min, const uint max)
|
||||
{
|
||||
return (uint)(x - min) < (max - min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe swap operation
|
||||
* @param a variable to swap with b
|
||||
* @param b variable to swap with a
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void Swap(T &a, T &b)
|
||||
{
|
||||
T t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a "fract" value 0..255 to "percent" value 0..100
|
||||
* @param i value to convert, range 0..255
|
||||
* @return value in range 0..100
|
||||
*/
|
||||
static inline uint ToPercent8(uint i)
|
||||
{
|
||||
assert(i < 256);
|
||||
return i * 101 >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a "fract" value 0..65535 to "percent" value 0..100
|
||||
* @param i value to convert, range 0..65535
|
||||
* @return value in range 0..100
|
||||
*/
|
||||
static inline uint ToPercent16(uint i)
|
||||
{
|
||||
assert(i < 65536);
|
||||
return i * 101 >> 16;
|
||||
}
|
||||
|
||||
int LeastCommonMultiple(int a, int b);
|
||||
int GreatestCommonDivisor(int a, int b);
|
||||
int DivideApprox(int a, int b);
|
||||
|
||||
/**
|
||||
* Computes ceil(a / b) for non-negative a and b.
|
||||
* @param a Numerator
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded up
|
||||
*/
|
||||
static inline uint CeilDiv(uint a, uint b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes ceil(a / b) * b for non-negative a and b.
|
||||
* @param a Numerator
|
||||
* @param b Denominator
|
||||
* @return a rounded up to the nearest multiple of b.
|
||||
*/
|
||||
static inline uint Ceil(uint a, uint b)
|
||||
{
|
||||
return CeilDiv(a, b) * b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes round(a / b) for signed a and unsigned b.
|
||||
* @param a Numerator
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded to nearest
|
||||
*/
|
||||
static inline int RoundDivSU(int a, uint b)
|
||||
{
|
||||
if (a > 0) {
|
||||
/* 0.5 is rounded to 1 */
|
||||
return (a + (int)b / 2) / (int)b;
|
||||
} else {
|
||||
/* -0.5 is rounded to 0 */
|
||||
return (a - ((int)b - 1) / 2) / (int)b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes (a / b) rounded away from zero.
|
||||
* @param a Numerator
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded away from zero
|
||||
*/
|
||||
static inline int DivAwayFromZero(int a, uint b)
|
||||
{
|
||||
const int _b = static_cast<int>(b);
|
||||
if (a > 0) {
|
||||
return (a + _b - 1) / _b;
|
||||
} else {
|
||||
/* Note: Behaviour of negative numerator division is truncation toward zero. */
|
||||
return (a - _b + 1) / _b;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 IntSqrt(uint32 num);
|
||||
|
||||
#endif /* MATH_FUNC_HPP */
|
||||
103
src/core/mem_func.hpp
Normal file
103
src/core/mem_func.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file mem_func.hpp Functions related to memory operations. */
|
||||
|
||||
#ifndef MEM_FUNC_HPP
|
||||
#define MEM_FUNC_HPP
|
||||
|
||||
#include "math_func.hpp"
|
||||
|
||||
/**
|
||||
* Type-safe version of memcpy().
|
||||
*
|
||||
* @param destination Pointer to the destination buffer
|
||||
* @param source Pointer to the source buffer
|
||||
* @param num number of items to be copied. (!not number of bytes!)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemCpyT(T *destination, const T *source, size_t num = 1)
|
||||
{
|
||||
memcpy(destination, source, num * sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe version of memmove().
|
||||
*
|
||||
* @param destination Pointer to the destination buffer
|
||||
* @param source Pointer to the source buffer
|
||||
* @param num number of items to be copied. (!not number of bytes!)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemMoveT(T *destination, const T *source, size_t num = 1)
|
||||
{
|
||||
memmove(destination, source, num * sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe version of memset().
|
||||
*
|
||||
* @param ptr Pointer to the destination buffer
|
||||
* @param value Value to be set
|
||||
* @param num number of items to be set (!not number of bytes!)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemSetT(T *ptr, byte value, size_t num = 1)
|
||||
{
|
||||
memset(ptr, value, num * sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe version of memcmp().
|
||||
*
|
||||
* @param ptr1 Pointer to the first buffer
|
||||
* @param ptr2 Pointer to the second buffer
|
||||
* @param num Number of items to compare. (!not number of bytes!)
|
||||
* @return an int value indicating the relationship between the content of the two buffers
|
||||
*/
|
||||
template <typename T>
|
||||
static inline int MemCmpT(const T *ptr1, const T *ptr2, size_t num = 1)
|
||||
{
|
||||
return memcmp(ptr1, ptr2, num * sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe memory reverse operation.
|
||||
* Reverse a block of memory in steps given by the
|
||||
* type of the pointers.
|
||||
*
|
||||
* @param ptr1 Start-pointer to the block of memory.
|
||||
* @param ptr2 End-pointer to the block of memory.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemReverseT(T *ptr1, T *ptr2)
|
||||
{
|
||||
assert(ptr1 != NULL && ptr2 != NULL);
|
||||
assert(ptr1 < ptr2);
|
||||
|
||||
do {
|
||||
Swap(*ptr1, *ptr2);
|
||||
} while (++ptr1 < --ptr2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe memory reverse operation (overloaded)
|
||||
*
|
||||
* @param ptr Pointer to the block of memory.
|
||||
* @param num The number of items we want to reverse.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemReverseT(T *ptr, size_t num)
|
||||
{
|
||||
assert(ptr != NULL);
|
||||
|
||||
MemReverseT(ptr, ptr + (num - 1));
|
||||
}
|
||||
|
||||
#endif /* MEM_FUNC_HPP */
|
||||
388
src/core/multimap.hpp
Normal file
388
src/core/multimap.hpp
Normal file
@@ -0,0 +1,388 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file multimap.hpp Multimap with deterministic ordering of items with equal keys. */
|
||||
|
||||
#ifndef MULTIMAP_HPP
|
||||
#define MULTIMAP_HPP
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
template<typename Tkey, typename Tvalue, typename Tcompare>
|
||||
class MultiMap;
|
||||
|
||||
/**
|
||||
* STL-style iterator for MultiMap.
|
||||
* @tparam Tmap_iter Iterator type for the map in the MultiMap.
|
||||
* @tparam Tlist_iter Iterator type for the lists in the MultiMap.
|
||||
* @tparam Tkey Key type of the MultiMap.
|
||||
* @tparam Tvalue Value type of the MultMap.
|
||||
* @tparam Tcompare Comparator type for keys of the MultiMap.
|
||||
*/
|
||||
template<class Tmap_iter, class Tlist_iter, class Tkey, class Tvalue, class Tcompare>
|
||||
class MultiMapIterator {
|
||||
protected:
|
||||
friend class MultiMap<Tkey, Tvalue, Tcompare>;
|
||||
typedef MultiMapIterator<Tmap_iter, Tlist_iter, Tkey, Tvalue, Tcompare> Self;
|
||||
|
||||
Tlist_iter list_iter; ///< Iterator pointing to current position in the current list of items with equal keys.
|
||||
Tmap_iter map_iter; ///< Iterator pointing to the position of the current list of items with equal keys in the map.
|
||||
|
||||
/**
|
||||
* Flag to show that the iterator has just "walked" a step in the map.
|
||||
* We cannot check the current list for that as we might have reached end() of the map. In that case we'd need to
|
||||
* set list_iter to some sort of "invalid" state, but that's impossible as operator== yields undefined behaviour
|
||||
* if the iterators don't belong to the same list and there is no list at end(). So if we created a static empty
|
||||
* list and an "invalid" iterator in that we could not determine if the iterator is invalid while it's valid. We
|
||||
* can also not determine if the map iterator is valid while we don't have the map; so in the end it's easiest to
|
||||
* just introduce an extra flag.
|
||||
*/
|
||||
bool list_valid;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Simple, dangerous constructor to allow later assignment with operator=.
|
||||
*/
|
||||
MultiMapIterator() : list_valid(false) {}
|
||||
|
||||
/**
|
||||
* Constructor to allow possibly const iterators to be assigned from possibly
|
||||
* non-const map iterators. You can assign end() like this.
|
||||
* @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const).
|
||||
* @param mi One such iterator.
|
||||
*/
|
||||
template<class Tnon_const>
|
||||
MultiMapIterator(Tnon_const mi) : map_iter(mi), list_valid(false) {}
|
||||
|
||||
/**
|
||||
* Constructor to allow specifying an exact position in map and list. You cannot
|
||||
* construct end() like this as the constructor will actually check li and mi->second
|
||||
* for list_valid.
|
||||
* @param mi Iterator in the map.
|
||||
* @param li Iterator in the list.
|
||||
*/
|
||||
MultiMapIterator(Tmap_iter mi, Tlist_iter li) : list_iter(li), map_iter(mi)
|
||||
{
|
||||
this->list_valid = (this->list_iter != this->map_iter->second.begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assignment iterator like constructor with the same signature.
|
||||
* @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const).
|
||||
* @param mi One such iterator.
|
||||
* @return This iterator.
|
||||
*/
|
||||
template<class Tnon_const>
|
||||
Self &operator=(Tnon_const mi)
|
||||
{
|
||||
this->map_iter = mi;
|
||||
this->list_valid = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereference operator. Works just like usual STL operator*() on various containers.
|
||||
* Doesn't do a lot of checks for sanity, just like STL.
|
||||
* @return The value associated with the item this iterator points to.
|
||||
*/
|
||||
Tvalue &operator*() const
|
||||
{
|
||||
assert(!this->map_iter->second.empty());
|
||||
return this->list_valid ?
|
||||
this->list_iter.operator*() :
|
||||
this->map_iter->second.begin().operator*();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as operator*(), but returns a pointer.
|
||||
* @return Pointer to the value this iterator points to.
|
||||
*/
|
||||
Tvalue *operator->() const
|
||||
{
|
||||
assert(!this->map_iter->second.empty());
|
||||
return this->list_valid ?
|
||||
this->list_iter.operator->() :
|
||||
this->map_iter->second.begin().operator->();
|
||||
}
|
||||
|
||||
inline const Tmap_iter &GetMapIter() const { return this->map_iter; }
|
||||
inline const Tlist_iter &GetListIter() const { return this->list_iter; }
|
||||
inline bool ListValid() const { return this->list_valid; }
|
||||
|
||||
const Tkey &GetKey() const { return this->map_iter->first; }
|
||||
|
||||
/**
|
||||
* Prefix increment operator. Increment the iterator and set it to the
|
||||
* next item in the MultiMap. This either increments the list iterator
|
||||
* or the map iterator and sets list_valid accordingly.
|
||||
* @return This iterator after incrementing.
|
||||
*/
|
||||
Self &operator++()
|
||||
{
|
||||
assert(!this->map_iter->second.empty());
|
||||
if (this->list_valid) {
|
||||
if (++this->list_iter == this->map_iter->second.end()) {
|
||||
++this->map_iter;
|
||||
this->list_valid = false;
|
||||
}
|
||||
} else {
|
||||
this->list_iter = ++(this->map_iter->second.begin());
|
||||
if (this->list_iter == this->map_iter->second.end()) {
|
||||
++this->map_iter;
|
||||
} else {
|
||||
this->list_valid = true;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Postfix increment operator. Same as prefix increment, but return the
|
||||
* previous state.
|
||||
* @param dummy param to mark postfix.
|
||||
* @return This iterator before incrementing.
|
||||
*/
|
||||
Self operator++(int)
|
||||
{
|
||||
Self tmp = *this;
|
||||
this->operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefix decrement operator. Decrement the iterator and set it to the
|
||||
* previous item in the MultiMap.
|
||||
* @return This iterator after decrementing.
|
||||
*/
|
||||
Self &operator--()
|
||||
{
|
||||
assert(!this->map_iter->second.empty());
|
||||
if (!this->list_valid) {
|
||||
--this->map_iter;
|
||||
this->list_iter = this->map_iter->second.end();
|
||||
assert(!this->map_iter->second.empty());
|
||||
}
|
||||
|
||||
this->list_valid = (--this->list_iter != this->map_iter->second.begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Postfix decrement operator. Same as prefix decrement, but return the
|
||||
* previous state.
|
||||
* @param dummy param to mark postfix.
|
||||
* @return This iterator before decrementing.
|
||||
*/
|
||||
Self operator--(int)
|
||||
{
|
||||
Self tmp = *this;
|
||||
this->operator--();
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/* Generic comparison functions for const/non-const MultiMap iterators and map iterators */
|
||||
|
||||
/**
|
||||
* Compare two MultiMap iterators. Iterators are equal if
|
||||
* 1. Their map iterators are equal.
|
||||
* 2. They agree about list_valid.
|
||||
* 3. If list_valid they agree about list_iter.
|
||||
* Lots of template parameters to make all possible const and non-const types of MultiMap iterators
|
||||
* (on maps with const and non-const values) comparable to each other.
|
||||
* @param iter1 First iterator to compare.
|
||||
* @param iter2 Second iterator to compare.
|
||||
* @return If iter1 and iter2 are equal.
|
||||
*/
|
||||
template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tlist_iter2, class Tkey, class Tvalue1, class Tvalue2, class Tcompare>
|
||||
bool operator==(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare> &iter1, const MultiMapIterator<Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare> &iter2)
|
||||
{
|
||||
if (iter1.GetMapIter() != iter2.GetMapIter()) return false;
|
||||
if (!iter1.ListValid()) return !iter2.ListValid();
|
||||
return iter2.ListValid() ?
|
||||
iter1.GetListIter() == iter2.GetListIter() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of operator==().
|
||||
* Lots of template parameters to make all possible const and non-const types of MultiMap iterators
|
||||
* (on maps with const and non-const values) comparable to each other.
|
||||
* @param iter1 First iterator to compare.
|
||||
* @param iter2 Second iterator to compare.
|
||||
* @return If iter1 and iter2 are not equal.
|
||||
*/
|
||||
template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tlist_iter2, class Tkey, class Tvalue1, class Tvalue2, class Tcompare>
|
||||
bool operator!=(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare> &iter1, const MultiMapIterator<Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare> &iter2)
|
||||
{
|
||||
return !(iter1 == iter2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a MultiMap iterator is at the begin of a list pointed to by the given map iterator.
|
||||
* Lots of template parameters to make all possible const and non-const types of MultiMap iterators
|
||||
* (on maps with const and non-const values) comparable to all possible types of map iterators.
|
||||
* @param iter1 MultiMap iterator.
|
||||
* @param iter2 Map iterator.
|
||||
* @return If iter1 points to the begin of the list pointed to by iter2.
|
||||
*/
|
||||
template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
|
||||
bool operator==(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1, const Tmap_iter2 &iter2)
|
||||
{
|
||||
return !iter1.ListValid() && iter1.GetMapIter() == iter2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of operator==() with same signature.
|
||||
* @param iter1 MultiMap iterator.
|
||||
* @param iter2 Map iterator.
|
||||
* @return If iter1 doesn't point to the begin of the list pointed to by iter2.
|
||||
*/
|
||||
template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
|
||||
bool operator!=(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1, const Tmap_iter2 &iter2)
|
||||
{
|
||||
return iter1.ListValid() || iter1.GetMapIter() != iter2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as operator==() with reversed order of arguments.
|
||||
* @param iter2 Map iterator.
|
||||
* @param iter1 MultiMap iterator.
|
||||
* @return If iter1 points to the begin of the list pointed to by iter2.
|
||||
*/
|
||||
template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
|
||||
bool operator==(const Tmap_iter2 &iter2, const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1)
|
||||
{
|
||||
return !iter1.ListValid() && iter1.GetMapIter() == iter2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as operator!=() with reversed order of arguments.
|
||||
* @param iter2 Map iterator.
|
||||
* @param iter1 MultiMap iterator.
|
||||
* @return If iter1 doesn't point to the begin of the list pointed to by iter2.
|
||||
*/
|
||||
template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
|
||||
bool operator!=(const Tmap_iter2 &iter2, const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1)
|
||||
{
|
||||
return iter1.ListValid() || iter1.GetMapIter() != iter2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hand-rolled multimap as map of lists. Behaves mostly like a list, but is sorted
|
||||
* by Tkey so that you can easily look up ranges of equal keys. Those ranges are
|
||||
* internally ordered in a deterministic way (contrary to STL multimap). All
|
||||
* STL-compatible members are named in STL style, all others are named in OpenTTD
|
||||
* style.
|
||||
*/
|
||||
template<typename Tkey, typename Tvalue, typename Tcompare = std::less<Tkey> >
|
||||
class MultiMap : public std::map<Tkey, std::list<Tvalue>, Tcompare > {
|
||||
public:
|
||||
typedef typename std::list<Tvalue> List;
|
||||
typedef typename List::iterator ListIterator;
|
||||
typedef typename List::const_iterator ConstListIterator;
|
||||
|
||||
typedef typename std::map<Tkey, List, Tcompare > Map;
|
||||
typedef typename Map::iterator MapIterator;
|
||||
typedef typename Map::const_iterator ConstMapIterator;
|
||||
|
||||
typedef MultiMapIterator<MapIterator, ListIterator, Tkey, Tvalue, Tcompare> iterator;
|
||||
typedef MultiMapIterator<ConstMapIterator, ConstListIterator, Tkey, const Tvalue, Tcompare> const_iterator;
|
||||
|
||||
/**
|
||||
* Erase the value pointed to by an iterator. The iterator may be invalid afterwards.
|
||||
* @param it Iterator pointing at some value.
|
||||
* @return Iterator to the element after the deleted one (or invalid).
|
||||
*/
|
||||
iterator erase(iterator it)
|
||||
{
|
||||
List &list = it.map_iter->second;
|
||||
assert(!list.empty());
|
||||
if (it.list_valid) {
|
||||
it.list_iter = list.erase(it.list_iter);
|
||||
/* This can't be the first list element as otherwise list_valid would have
|
||||
* to be false. So the list cannot be empty here. */
|
||||
if (it.list_iter == list.end()) {
|
||||
++it.map_iter;
|
||||
it.list_valid = false;
|
||||
}
|
||||
} else {
|
||||
list.erase(list.begin());
|
||||
if (list.empty()) this->Map::erase(it.map_iter++);
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a value at the end of the range with the specified key.
|
||||
* @param key Key to be inserted at.
|
||||
* @param val Value to be inserted.
|
||||
*/
|
||||
void Insert(const Tkey &key, const Tvalue &val)
|
||||
{
|
||||
List &list = (*this)[key];
|
||||
list.push_back(val);
|
||||
assert(!list.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Count all items in this MultiMap. This involves iterating over the map.
|
||||
* @return Number of items in the MultiMap.
|
||||
*/
|
||||
size_t size() const
|
||||
{
|
||||
size_t ret = 0;
|
||||
for (ConstMapIterator it = this->Map::begin(); it != this->Map::end(); ++it) {
|
||||
ret += it->second.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of ranges with equal keys in this MultiMap.
|
||||
* @return Number of ranges with equal keys.
|
||||
*/
|
||||
size_t MapSize() const
|
||||
{
|
||||
return this->Map::size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pair of iterators specifying a range of items with equal keys.
|
||||
* @param key Key to look for.
|
||||
* @return Range of items with given key.
|
||||
*/
|
||||
std::pair<iterator, iterator> equal_range(const Tkey &key)
|
||||
{
|
||||
MapIterator begin(this->lower_bound(key));
|
||||
if (begin != this->Map::end() && begin->first == key) {
|
||||
MapIterator end = begin;
|
||||
return std::make_pair(begin, ++end);
|
||||
}
|
||||
return std::make_pair(begin, begin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pair of constant iterators specifying a range of items with equal keys.
|
||||
* @param key Key to look for.
|
||||
* @return Constant range of items with given key.
|
||||
*/
|
||||
std::pair<const_iterator, const_iterator> equal_range(const Tkey &key) const
|
||||
{
|
||||
ConstMapIterator begin(this->lower_bound(key));
|
||||
if (begin != this->Map::end() && begin->first == key) {
|
||||
ConstMapIterator end = begin;
|
||||
return std::make_pair(begin, ++end);
|
||||
}
|
||||
return std::make_pair(begin, begin);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* MULTIMAP_HPP */
|
||||
157
src/core/overflowsafe_type.hpp
Normal file
157
src/core/overflowsafe_type.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file overflowsafe_type.hpp An overflow safe integer-like type. */
|
||||
|
||||
#ifndef OVERFLOWSAFE_TYPE_HPP
|
||||
#define OVERFLOWSAFE_TYPE_HPP
|
||||
|
||||
#include "math_func.hpp"
|
||||
|
||||
/**
|
||||
* Overflow safe template for integers, i.e. integers that will never overflow
|
||||
* you multiply the maximum value with 2, or add 2, or subtract something from
|
||||
* the minimum value, etc.
|
||||
* @param T the type these integers are stored with.
|
||||
* @param T_MAX the maximum value for the integers.
|
||||
* @param T_MIN the minimum value for the integers.
|
||||
*/
|
||||
template <class T, T T_MAX, T T_MIN>
|
||||
class OverflowSafeInt
|
||||
{
|
||||
private:
|
||||
/** The non-overflow safe backend to store the value in. */
|
||||
T m_value;
|
||||
public:
|
||||
OverflowSafeInt() : m_value(0) { }
|
||||
|
||||
OverflowSafeInt(const OverflowSafeInt& other) { this->m_value = other.m_value; }
|
||||
OverflowSafeInt(const int64 int_) { this->m_value = int_; }
|
||||
|
||||
inline OverflowSafeInt& operator = (const OverflowSafeInt& other) { this->m_value = other.m_value; return *this; }
|
||||
|
||||
inline OverflowSafeInt operator - () const { return OverflowSafeInt(-this->m_value); }
|
||||
|
||||
/**
|
||||
* Safe implementation of addition.
|
||||
* @param other the amount to add
|
||||
* @note when the addition would yield more than T_MAX (or less than T_MIN),
|
||||
* it will be T_MAX (respectively T_MIN).
|
||||
*/
|
||||
inline OverflowSafeInt& operator += (const OverflowSafeInt& other)
|
||||
{
|
||||
if ((T_MAX - abs(other.m_value)) < abs(this->m_value) &&
|
||||
(this->m_value < 0) == (other.m_value < 0)) {
|
||||
this->m_value = (this->m_value < 0) ? T_MIN : T_MAX ;
|
||||
} else {
|
||||
this->m_value += other.m_value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Operators for addition and subtraction */
|
||||
inline OverflowSafeInt operator + (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result += other; return result; }
|
||||
inline OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64)other; return result; }
|
||||
inline OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64)other; return result; }
|
||||
inline OverflowSafeInt& operator -= (const OverflowSafeInt& other) { return *this += (-other); }
|
||||
inline OverflowSafeInt operator - (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result -= other; return result; }
|
||||
inline OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; }
|
||||
inline OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; }
|
||||
|
||||
inline OverflowSafeInt& operator ++ () { return *this += 1; }
|
||||
inline OverflowSafeInt& operator -- () { return *this += -1; }
|
||||
inline OverflowSafeInt operator ++ (int) { OverflowSafeInt org = *this; *this += 1; return org; }
|
||||
inline OverflowSafeInt operator -- (int) { OverflowSafeInt org = *this; *this += -1; return org; }
|
||||
|
||||
/**
|
||||
* Safe implementation of multiplication.
|
||||
* @param factor the factor to multiply this with.
|
||||
* @note when the multiplication would yield more than T_MAX (or less than T_MIN),
|
||||
* it will be T_MAX (respectively T_MIN).
|
||||
*/
|
||||
inline OverflowSafeInt& operator *= (const int factor)
|
||||
{
|
||||
if (factor != 0 && (T_MAX / abs(factor)) < abs(this->m_value)) {
|
||||
this->m_value = ((this->m_value < 0) == (factor < 0)) ? T_MAX : T_MIN ;
|
||||
} else {
|
||||
this->m_value *= factor ;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Operators for multiplication */
|
||||
inline OverflowSafeInt operator * (const int64 factor) const { OverflowSafeInt result = *this; result *= factor; return result; }
|
||||
inline OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline OverflowSafeInt operator * (const uint16 factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline OverflowSafeInt operator * (const byte factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
|
||||
/* Operators for division */
|
||||
inline OverflowSafeInt& operator /= (const int64 divisor) { this->m_value /= divisor; return *this; }
|
||||
inline OverflowSafeInt operator / (const OverflowSafeInt& divisor) const { OverflowSafeInt result = *this; result /= divisor.m_value; return result; }
|
||||
inline OverflowSafeInt operator / (const int divisor) const { OverflowSafeInt result = *this; result /= divisor; return result; }
|
||||
inline OverflowSafeInt operator / (const uint divisor) const { OverflowSafeInt result = *this; result /= (int)divisor; return result; }
|
||||
|
||||
/* Operators for modulo */
|
||||
inline OverflowSafeInt& operator %= (const int divisor) { this->m_value %= divisor; return *this; }
|
||||
inline OverflowSafeInt operator % (const int divisor) const { OverflowSafeInt result = *this; result %= divisor; return result; }
|
||||
|
||||
/* Operators for shifting */
|
||||
inline OverflowSafeInt& operator <<= (const int shift) { this->m_value <<= shift; return *this; }
|
||||
inline OverflowSafeInt operator << (const int shift) const { OverflowSafeInt result = *this; result <<= shift; return result; }
|
||||
inline OverflowSafeInt& operator >>= (const int shift) { this->m_value >>= shift; return *this; }
|
||||
inline OverflowSafeInt operator >> (const int shift) const { OverflowSafeInt result = *this; result >>= shift; return result; }
|
||||
|
||||
/* Operators for (in)equality when comparing overflow safe ints */
|
||||
inline bool operator == (const OverflowSafeInt& other) const { return this->m_value == other.m_value; }
|
||||
inline bool operator != (const OverflowSafeInt& other) const { return !(*this == other); }
|
||||
inline bool operator > (const OverflowSafeInt& other) const { return this->m_value > other.m_value; }
|
||||
inline bool operator >= (const OverflowSafeInt& other) const { return this->m_value >= other.m_value; }
|
||||
inline bool operator < (const OverflowSafeInt& other) const { return !(*this >= other); }
|
||||
inline bool operator <= (const OverflowSafeInt& other) const { return !(*this > other); }
|
||||
|
||||
/* Operators for (in)equality when comparing non-overflow safe ints */
|
||||
inline bool operator == (const int other) const { return this->m_value == other; }
|
||||
inline bool operator != (const int other) const { return !(*this == other); }
|
||||
inline bool operator > (const int other) const { return this->m_value > other; }
|
||||
inline bool operator >= (const int other) const { return this->m_value >= other; }
|
||||
inline bool operator < (const int other) const { return !(*this >= other); }
|
||||
inline bool operator <= (const int other) const { return !(*this > other); }
|
||||
|
||||
inline operator int64 () const { return this->m_value; }
|
||||
};
|
||||
|
||||
/* Sometimes we got int64 operator OverflowSafeInt instead of vice versa. Handle that properly */
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator + (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator - (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator * (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator / (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got int operator OverflowSafeInt instead of vice versa. Handle that properly */
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator + (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator - (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator * (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator / (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got uint operator OverflowSafeInt instead of vice versa. Handle that properly */
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator + (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator - (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator * (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator / (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got byte operator OverflowSafeInt instead of vice versa. Handle that properly */
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator + (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + (uint)a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator - (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + (uint)a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator * (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * (uint)a; }
|
||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator / (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
|
||||
|
||||
typedef OverflowSafeInt<int64, INT64_MAX, INT64_MIN> OverflowSafeInt64;
|
||||
typedef OverflowSafeInt<int32, INT32_MAX, INT32_MIN> OverflowSafeInt32;
|
||||
|
||||
#endif /* OVERFLOWSAFE_TYPE_HPP */
|
||||
40
src/core/pool_func.cpp
Normal file
40
src/core/pool_func.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file pool_func.cpp Implementation of PoolBase methods. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "pool_type.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Destructor removes this object from the pool vector and
|
||||
* deletes the vector itself if this was the last item removed.
|
||||
*/
|
||||
/* virtual */ PoolBase::~PoolBase()
|
||||
{
|
||||
PoolVector *pools = PoolBase::GetPools();
|
||||
pools->Erase(pools->Find(this));
|
||||
if (pools->Length() == 0) delete pools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean all pools of given type.
|
||||
* @param pt pool types to clean.
|
||||
*/
|
||||
/* static */ void PoolBase::Clean(PoolType pt)
|
||||
{
|
||||
PoolVector *pools = PoolBase::GetPools();
|
||||
PoolBase **end = pools->End();
|
||||
for (PoolBase **ppool = pools->Begin(); ppool != end; ppool++) {
|
||||
PoolBase *pool = *ppool;
|
||||
if (pool->type & pt) pool->CleanPool();
|
||||
}
|
||||
}
|
||||
232
src/core/pool_func.hpp
Normal file
232
src/core/pool_func.hpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file pool_func.hpp Some methods of Pool are placed here in order to reduce compilation time and binary size. */
|
||||
|
||||
#ifndef POOL_FUNC_HPP
|
||||
#define POOL_FUNC_HPP
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
#include "pool_type.hpp"
|
||||
|
||||
/**
|
||||
* Helper for defining the method's signature.
|
||||
* @param type The return type of the method.
|
||||
*/
|
||||
#define DEFINE_POOL_METHOD(type) \
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
|
||||
type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
|
||||
|
||||
/**
|
||||
* Create a clean pool.
|
||||
* @param name The name for the pool.
|
||||
*/
|
||||
DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
|
||||
PoolBase(Tpool_type),
|
||||
name(name),
|
||||
size(0),
|
||||
first_free(0),
|
||||
first_unused(0),
|
||||
items(0),
|
||||
#ifdef OTTD_ASSERT
|
||||
checked(0),
|
||||
#endif /* OTTD_ASSERT */
|
||||
cleaning(false),
|
||||
data(NULL),
|
||||
alloc_cache(NULL)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Resizes the pool so 'index' can be addressed
|
||||
* @param index index we will allocate later
|
||||
* @pre index >= this->size
|
||||
* @pre index < Tmax_size
|
||||
*/
|
||||
DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
|
||||
{
|
||||
assert(index >= this->size);
|
||||
assert(index < Tmax_size);
|
||||
|
||||
size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
|
||||
|
||||
this->data = ReallocT(this->data, new_size);
|
||||
MemSetT(this->data + this->size, 0, new_size - this->size);
|
||||
|
||||
this->size = new_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for first free index
|
||||
* @return first free index, NO_FREE_ITEM on failure
|
||||
*/
|
||||
DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
|
||||
{
|
||||
size_t index = this->first_free;
|
||||
|
||||
for (; index < this->first_unused; index++) {
|
||||
if (this->data[index] == NULL) return index;
|
||||
}
|
||||
|
||||
if (index < this->size) {
|
||||
return index;
|
||||
}
|
||||
|
||||
assert(index == this->size);
|
||||
assert(this->first_unused == this->size);
|
||||
|
||||
if (index < Tmax_size) {
|
||||
this->ResizeFor(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
assert(this->items == Tmax_size);
|
||||
|
||||
return NO_FREE_ITEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes given index valid
|
||||
* @param size size of item
|
||||
* @param index index of item
|
||||
* @pre index < this->size
|
||||
* @pre this->Get(index) == NULL
|
||||
*/
|
||||
DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
|
||||
{
|
||||
assert(this->data[index] == NULL);
|
||||
|
||||
this->first_unused = max(this->first_unused, index + 1);
|
||||
this->items++;
|
||||
|
||||
Titem *item;
|
||||
if (Tcache && this->alloc_cache != NULL) {
|
||||
assert(sizeof(Titem) == size);
|
||||
item = (Titem *)this->alloc_cache;
|
||||
this->alloc_cache = this->alloc_cache->next;
|
||||
if (Tzero) {
|
||||
/* Explicitly casting to (void *) prevents a clang warning -
|
||||
* we are actually memsetting a (not-yet-constructed) object */
|
||||
memset((void *)item, 0, sizeof(Titem));
|
||||
}
|
||||
} else if (Tzero) {
|
||||
item = (Titem *)CallocT<byte>(size);
|
||||
} else {
|
||||
item = (Titem *)MallocT<byte>(size);
|
||||
}
|
||||
this->data[index] = item;
|
||||
item->index = (Tindex)(uint)index;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates new item
|
||||
* @param size size of item
|
||||
* @return pointer to allocated item
|
||||
* @note error() on failure! (no free item)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
{
|
||||
size_t index = this->FindFirstFree();
|
||||
|
||||
#ifdef OTTD_ASSERT
|
||||
assert(this->checked != 0);
|
||||
this->checked--;
|
||||
#endif /* OTTD_ASSERT */
|
||||
if (index == NO_FREE_ITEM) {
|
||||
error("%s: no more free items", this->name);
|
||||
}
|
||||
|
||||
this->first_free = index + 1;
|
||||
return this->AllocateItem(size, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates new item with given index
|
||||
* @param size size of item
|
||||
* @param index index of item
|
||||
* @return pointer to allocated item
|
||||
* @note SlErrorCorruptFmt() on failure! (index out of range or already used)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
|
||||
{
|
||||
extern void NORETURN SlErrorCorruptFmt(const char *format, ...);
|
||||
|
||||
if (index >= Tmax_size) {
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
|
||||
}
|
||||
|
||||
if (index >= this->size) this->ResizeFor(index);
|
||||
|
||||
if (this->data[index] != NULL) {
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " already in use", this->name, index);
|
||||
}
|
||||
|
||||
return this->AllocateItem(size, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates memory used by this index and marks item as free
|
||||
* @param index item to deallocate
|
||||
* @pre unit is allocated (non-NULL)
|
||||
* @note 'delete NULL' doesn't cause call of this function, so it is safe
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
|
||||
{
|
||||
assert(index < this->size);
|
||||
assert(this->data[index] != NULL);
|
||||
if (Tcache) {
|
||||
AllocCache *ac = (AllocCache *)this->data[index];
|
||||
ac->next = this->alloc_cache;
|
||||
this->alloc_cache = ac;
|
||||
} else {
|
||||
free(this->data[index]);
|
||||
}
|
||||
this->data[index] = NULL;
|
||||
this->first_free = min(this->first_free, index);
|
||||
this->items--;
|
||||
if (!this->cleaning) Titem::PostDestructor(index);
|
||||
}
|
||||
|
||||
/** Destroys all items in the pool and resets all member variables. */
|
||||
DEFINE_POOL_METHOD(void)::CleanPool()
|
||||
{
|
||||
this->cleaning = true;
|
||||
for (size_t i = 0; i < this->first_unused; i++) {
|
||||
delete this->Get(i); // 'delete NULL;' is very valid
|
||||
}
|
||||
assert(this->items == 0);
|
||||
free(this->data);
|
||||
this->first_unused = this->first_free = this->size = 0;
|
||||
this->data = NULL;
|
||||
this->cleaning = false;
|
||||
|
||||
if (Tcache) {
|
||||
while (this->alloc_cache != NULL) {
|
||||
AllocCache *ac = this->alloc_cache;
|
||||
this->alloc_cache = ac->next;
|
||||
free(ac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEFINE_POOL_METHOD
|
||||
|
||||
/**
|
||||
* Force instantiation of pool methods so we don't get linker errors.
|
||||
* Only methods accessed from methods defined in pool.hpp need to be
|
||||
* forcefully instantiated.
|
||||
*/
|
||||
#define INSTANTIATE_POOL_METHODS(name) \
|
||||
template void * name ## Pool::GetNew(size_t size); \
|
||||
template void * name ## Pool::GetNew(size_t size, size_t index); \
|
||||
template void name ## Pool::FreeItem(size_t index); \
|
||||
template void name ## Pool::CleanPool();
|
||||
|
||||
#endif /* POOL_FUNC_HPP */
|
||||
322
src/core/pool_type.hpp
Normal file
322
src/core/pool_type.hpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file pool_type.hpp Defintion of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle, Town, and other indexed items. */
|
||||
|
||||
#ifndef POOL_TYPE_HPP
|
||||
#define POOL_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include "enum_type.hpp"
|
||||
|
||||
/** Various types of a pool. */
|
||||
enum PoolType {
|
||||
PT_NONE = 0x00, ///< No pool is selected.
|
||||
PT_NORMAL = 0x01, ///< Normal pool containing game objects.
|
||||
PT_NCLIENT = 0x02, ///< Network client pools.
|
||||
PT_NADMIN = 0x04, ///< Network admin pool.
|
||||
PT_DATA = 0x08, ///< NewGRF or other data, that is not reset together with normal pools.
|
||||
PT_ALL = 0x0F, ///< All pool types.
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(PoolType)
|
||||
|
||||
typedef SmallVector<struct PoolBase *, 4> PoolVector; ///< Vector of pointers to PoolBase
|
||||
|
||||
/** Base class for base of all pools. */
|
||||
struct PoolBase {
|
||||
const PoolType type; ///< Type of this pool.
|
||||
|
||||
/**
|
||||
* Function used to access the vector of all pools.
|
||||
* @return pointer to vector of all pools
|
||||
*/
|
||||
static PoolVector *GetPools()
|
||||
{
|
||||
static PoolVector *pools = new PoolVector();
|
||||
return pools;
|
||||
}
|
||||
|
||||
static void Clean(PoolType);
|
||||
|
||||
/**
|
||||
* Constructor registers this object in the pool vector.
|
||||
* @param pt type of this pool.
|
||||
*/
|
||||
PoolBase(PoolType pt) : type(pt)
|
||||
{
|
||||
*PoolBase::GetPools()->Append() = this;
|
||||
}
|
||||
|
||||
virtual ~PoolBase();
|
||||
|
||||
/**
|
||||
* Virtual method that deletes all items in the pool.
|
||||
*/
|
||||
virtual void CleanPool() = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Dummy private copy constructor to prevent compilers from
|
||||
* copying the structure, which fails due to GetPools().
|
||||
*/
|
||||
PoolBase(const PoolBase &other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for all pools.
|
||||
* @tparam Titem Type of the class/struct that is going to be pooled
|
||||
* @tparam Tindex Type of the index for this pool
|
||||
* @tparam Tgrowth_step Size of growths; if the pool is full increase the size by this amount
|
||||
* @tparam Tmax_size Maximum size of the pool
|
||||
* @tparam Tpool_type Type of this pool
|
||||
* @tparam Tcache Whether to perform 'alloc' caching, i.e. don't actually free/malloc just reuse the memory
|
||||
* @tparam Tzero Whether to zero the memory
|
||||
* @warning when Tcache is enabled *all* instances of this pool's item must be of the same size.
|
||||
*/
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type = PT_NORMAL, bool Tcache = false, bool Tzero = true>
|
||||
struct Pool : PoolBase {
|
||||
/* Ensure Tmax_size is within the bounds of Tindex. */
|
||||
assert_compile((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0);
|
||||
|
||||
static const size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside
|
||||
|
||||
const char * const name; ///< Name of this pool
|
||||
|
||||
size_t size; ///< Current allocated size
|
||||
size_t first_free; ///< No item with index lower than this is free (doesn't say anything about this one!)
|
||||
size_t first_unused; ///< This and all higher indexes are free (doesn't say anything about first_unused-1 !)
|
||||
size_t items; ///< Number of used indexes (non-NULL)
|
||||
#ifdef OTTD_ASSERT
|
||||
size_t checked; ///< Number of items we checked for
|
||||
#endif /* OTTD_ASSERT */
|
||||
bool cleaning; ///< True if cleaning pool (deleting all items)
|
||||
|
||||
Titem **data; ///< Pointer to array of pointers to Titem
|
||||
|
||||
Pool(const char *name);
|
||||
virtual void CleanPool();
|
||||
|
||||
/**
|
||||
* Returns Titem with given index
|
||||
* @param index of item to get
|
||||
* @return pointer to Titem
|
||||
* @pre index < this->first_unused
|
||||
*/
|
||||
inline Titem *Get(size_t index)
|
||||
{
|
||||
assert(index < this->first_unused);
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether given index can be used to get valid (non-NULL) Titem
|
||||
* @param index index to examine
|
||||
* @return true if PoolItem::Get(index) will return non-NULL pointer
|
||||
*/
|
||||
inline bool IsValidID(size_t index)
|
||||
{
|
||||
return index < this->first_unused && this->Get(index) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether we can allocate 'n' items
|
||||
* @param n number of items we want to allocate
|
||||
* @return true if 'n' items can be allocated
|
||||
*/
|
||||
inline bool CanAllocate(size_t n = 1)
|
||||
{
|
||||
bool ret = this->items <= Tmax_size - n;
|
||||
#ifdef OTTD_ASSERT
|
||||
this->checked = ret ? n : 0;
|
||||
#endif /* OTTD_ASSERT */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all PoolItems
|
||||
* @tparam Tpool The pool this item is going to be part of
|
||||
*/
|
||||
template <struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> *Tpool>
|
||||
struct PoolItem {
|
||||
Tindex index; ///< Index of this pool item
|
||||
|
||||
/**
|
||||
* Allocates space for new Titem
|
||||
* @param size size of Titem
|
||||
* @return pointer to allocated memory
|
||||
* @note can never fail (return NULL), use CanAllocate() to check first!
|
||||
*/
|
||||
inline void *operator new(size_t size)
|
||||
{
|
||||
return Tpool->GetNew(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks Titem as free. Its memory is released
|
||||
* @param p memory to free
|
||||
* @note the item has to be allocated in the pool!
|
||||
*/
|
||||
inline void operator delete(void *p)
|
||||
{
|
||||
if (p == NULL) return;
|
||||
Titem *pn = (Titem *)p;
|
||||
assert(pn == Tpool->Get(pn->index));
|
||||
Tpool->FreeItem(pn->index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates space for new Titem with given index
|
||||
* @param size size of Titem
|
||||
* @param index index of item
|
||||
* @return pointer to allocated memory
|
||||
* @note can never fail (return NULL), use CanAllocate() to check first!
|
||||
* @pre index has to be unused! Else it will crash
|
||||
*/
|
||||
inline void *operator new(size_t size, size_t index)
|
||||
{
|
||||
return Tpool->GetNew(size, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates space for new Titem at given memory address
|
||||
* @param size size of Titem
|
||||
* @param ptr where are we allocating the item?
|
||||
* @return pointer to allocated memory (== ptr)
|
||||
* @note use of this is strongly discouraged
|
||||
* @pre the memory must not be allocated in the Pool!
|
||||
*/
|
||||
inline void *operator new(size_t size, void *ptr)
|
||||
{
|
||||
for (size_t i = 0; i < Tpool->first_unused; i++) {
|
||||
/* Don't allow creating new objects over existing.
|
||||
* Even if we called the destructor and reused this memory,
|
||||
* we don't know whether 'size' and size of currently allocated
|
||||
* memory are the same (because of possible inheritance).
|
||||
* Use { size_t index = item->index; delete item; new (index) item; }
|
||||
* instead to make sure destructor is called and no memory leaks. */
|
||||
assert(ptr != Tpool->data[i]);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/** Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function() */
|
||||
|
||||
/**
|
||||
* Tests whether we can allocate 'n' items
|
||||
* @param n number of items we want to allocate
|
||||
* @return true if 'n' items can be allocated
|
||||
*/
|
||||
static inline bool CanAllocateItem(size_t n = 1)
|
||||
{
|
||||
return Tpool->CanAllocate(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current state of pool cleaning - yes or no
|
||||
* @return true iff we are cleaning the pool now
|
||||
*/
|
||||
static inline bool CleaningPool()
|
||||
{
|
||||
return Tpool->cleaning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether given index can be used to get valid (non-NULL) Titem
|
||||
* @param index index to examine
|
||||
* @return true if PoolItem::Get(index) will return non-NULL pointer
|
||||
*/
|
||||
static inline bool IsValidID(size_t index)
|
||||
{
|
||||
return Tpool->IsValidID(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Titem with given index
|
||||
* @param index of item to get
|
||||
* @return pointer to Titem
|
||||
* @pre index < this->first_unused
|
||||
*/
|
||||
static inline Titem *Get(size_t index)
|
||||
{
|
||||
return Tpool->Get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Titem with given index
|
||||
* @param index of item to get
|
||||
* @return pointer to Titem
|
||||
* @note returns NULL for invalid index
|
||||
*/
|
||||
static inline Titem *GetIfValid(size_t index)
|
||||
{
|
||||
return index < Tpool->first_unused ? Tpool->Get(index) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first unused index. Useful when iterating over
|
||||
* all pool items.
|
||||
* @return first unused index
|
||||
*/
|
||||
static inline size_t GetPoolSize()
|
||||
{
|
||||
return Tpool->first_unused;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of valid items in the pool
|
||||
* @return number of valid items in the pool
|
||||
*/
|
||||
static inline size_t GetNumItems()
|
||||
{
|
||||
return Tpool->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function called after destructor of each member.
|
||||
* If you want to use it, override it in PoolItem's subclass.
|
||||
* @param index index of deleted item
|
||||
* @note when this function is called, PoolItem::Get(index) == NULL.
|
||||
* @note it's called only when !CleaningPool()
|
||||
*/
|
||||
static inline void PostDestructor(size_t index) { }
|
||||
};
|
||||
|
||||
private:
|
||||
static const size_t NO_FREE_ITEM = MAX_UVALUE(size_t); ///< Constant to indicate we can't allocate any more items
|
||||
|
||||
/**
|
||||
* Helper struct to cache 'freed' PoolItems so we
|
||||
* do not need to allocate them again.
|
||||
*/
|
||||
struct AllocCache {
|
||||
/** The next in our 'cache' */
|
||||
AllocCache *next;
|
||||
};
|
||||
|
||||
/** Cache of freed pointers */
|
||||
AllocCache *alloc_cache;
|
||||
|
||||
void *AllocateItem(size_t size, size_t index);
|
||||
void ResizeFor(size_t index);
|
||||
size_t FindFirstFree();
|
||||
|
||||
void *GetNew(size_t size);
|
||||
void *GetNew(size_t size, size_t index);
|
||||
|
||||
void FreeItem(size_t index);
|
||||
};
|
||||
|
||||
#define FOR_ALL_ITEMS_FROM(type, iter, var, start) \
|
||||
for (size_t iter = start; var = NULL, iter < type::GetPoolSize(); iter++) \
|
||||
if ((var = type::Get(iter)) != NULL)
|
||||
|
||||
#define FOR_ALL_ITEMS(type, iter, var) FOR_ALL_ITEMS_FROM(type, iter, var, 0)
|
||||
|
||||
#endif /* POOL_TYPE_HPP */
|
||||
87
src/core/random_func.cpp
Normal file
87
src/core/random_func.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file random_func.cpp Implementation of the pseudo random generator. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "random_func.hpp"
|
||||
#include "bitmath_func.hpp"
|
||||
|
||||
#ifdef RANDOM_DEBUG
|
||||
#include "../network/network.h"
|
||||
#include "../network/network_server.h"
|
||||
#include "../network/network_internal.h"
|
||||
#include "../company_func.h"
|
||||
#include "../fileio_func.h"
|
||||
#include "../date_func.h"
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
Randomizer _random, _interactive_random;
|
||||
|
||||
/**
|
||||
* Generate the next pseudo random number
|
||||
* @return the random number
|
||||
*/
|
||||
uint32 Randomizer::Next()
|
||||
{
|
||||
const uint32 s = this->state[0];
|
||||
const uint32 t = this->state[1];
|
||||
|
||||
this->state[0] = s + ROR(t ^ 0x1234567F, 7) + 1;
|
||||
return this->state[1] = ROR(s, 3) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the next pseudo random number scaled to \a limit, excluding \a limit
|
||||
* itself.
|
||||
* @param limit Limit of the range to be generated from.
|
||||
* @return Random number in [0,\a limit)
|
||||
*/
|
||||
uint32 Randomizer::Next(uint32 limit)
|
||||
{
|
||||
return ((uint64)this->Next() * (uint64)limit) >> 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)set the state of the random number generator.
|
||||
* @param seed the new state
|
||||
*/
|
||||
void Randomizer::SetSeed(uint32 seed)
|
||||
{
|
||||
this->state[0] = seed;
|
||||
this->state[1] = seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)set the state of the random number generators.
|
||||
* @param seed the new state
|
||||
*/
|
||||
void SetRandomSeed(uint32 seed)
|
||||
{
|
||||
_random.SetSeed(seed);
|
||||
_interactive_random.SetSeed(seed * 0x1234567);
|
||||
}
|
||||
|
||||
#ifdef RANDOM_DEBUG
|
||||
uint32 DoRandom(int line, const char *file)
|
||||
{
|
||||
if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) {
|
||||
DEBUG(random, 0, "%08x; %02x; %04x; %02x; %s:%d", _date, _date_fract, _frame_counter, (byte)_current_company, file, line);
|
||||
}
|
||||
|
||||
return _random.Next();
|
||||
}
|
||||
|
||||
uint32 DoRandomRange(uint32 limit, int line, const char *file)
|
||||
{
|
||||
return ((uint64)DoRandom(line, file) * (uint64)limit) >> 32;
|
||||
}
|
||||
#endif /* RANDOM_DEBUG */
|
||||
164
src/core/random_func.hpp
Normal file
164
src/core/random_func.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file random_func.hpp Pseudo random number generator. */
|
||||
|
||||
#ifndef RANDOM_FUNC_HPP
|
||||
#define RANDOM_FUNC_HPP
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Apple already has Random declared */
|
||||
#define Random OTTD_Random
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
/**
|
||||
* Structure to encapsulate the pseudo random number generators.
|
||||
*/
|
||||
struct Randomizer {
|
||||
/** The state of the randomizer */
|
||||
uint32 state[2];
|
||||
|
||||
uint32 Next();
|
||||
uint32 Next(uint32 limit);
|
||||
void SetSeed(uint32 seed);
|
||||
};
|
||||
extern Randomizer _random; ///< Random used in the game state calculations
|
||||
extern Randomizer _interactive_random; ///< Random used everywhere else, where it does not (directly) influence the game state
|
||||
|
||||
/** Stores the state of all random number generators */
|
||||
struct SavedRandomSeeds {
|
||||
Randomizer random;
|
||||
Randomizer interactive_random;
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves the current seeds
|
||||
* @param storage Storage for saving
|
||||
*/
|
||||
static inline void SaveRandomSeeds(SavedRandomSeeds *storage)
|
||||
{
|
||||
storage->random = _random;
|
||||
storage->interactive_random = _interactive_random;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores previously saved seeds
|
||||
* @param storage Storage where SaveRandomSeeds() stored th seeds
|
||||
*/
|
||||
static inline void RestoreRandomSeeds(const SavedRandomSeeds &storage)
|
||||
{
|
||||
_random = storage.random;
|
||||
_interactive_random = storage.interactive_random;
|
||||
}
|
||||
|
||||
void SetRandomSeed(uint32 seed);
|
||||
#ifdef RANDOM_DEBUG
|
||||
#ifdef __APPLE__
|
||||
#define OTTD_Random() DoRandom(__LINE__, __FILE__)
|
||||
#else
|
||||
#define Random() DoRandom(__LINE__, __FILE__)
|
||||
#endif
|
||||
uint32 DoRandom(int line, const char *file);
|
||||
#define RandomRange(limit) DoRandomRange(limit, __LINE__, __FILE__)
|
||||
uint32 DoRandomRange(uint32 limit, int line, const char *file);
|
||||
#else
|
||||
static inline uint32 Random()
|
||||
{
|
||||
return _random.Next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick a random number between 0 and \a limit - 1, inclusive. That means 0
|
||||
* can be returned and \a limit - 1 can be returned, but \a limit can not be
|
||||
* returned.
|
||||
* @param limit Limit for the range to be picked from.
|
||||
* @return A random number in [0,\a limit).
|
||||
*/
|
||||
static inline uint32 RandomRange(uint32 limit)
|
||||
{
|
||||
return _random.Next(limit);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint32 InteractiveRandom()
|
||||
{
|
||||
return _interactive_random.Next();
|
||||
}
|
||||
|
||||
static inline uint32 InteractiveRandomRange(uint32 limit)
|
||||
{
|
||||
return _interactive_random.Next(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given randomize-number is below a given probability.
|
||||
*
|
||||
* This function is used to check if the given probability by the fraction of (a/b)
|
||||
* is greater than low 16 bits of the given randomize-number r.
|
||||
*
|
||||
* Do not use this function twice on the same random 16 bits as it will yield
|
||||
* the same result. One can use a random number for two calls to Chance16I,
|
||||
* where one call sends the low 16 bits and the other the high 16 bits.
|
||||
*
|
||||
* @param a The numerator of the fraction
|
||||
* @param b The denominator of the fraction, must of course not be null
|
||||
* @param r The given randomize-number
|
||||
* @return True if the probability given by r is less or equal to (a/b)
|
||||
*/
|
||||
static inline bool Chance16I(const uint a, const uint b, const uint32 r)
|
||||
{
|
||||
assert(b != 0);
|
||||
return (((uint16)r * b + b / 2) >> 16) < a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips a coin with given probability.
|
||||
*
|
||||
* This function returns true with (a/b) probability.
|
||||
*
|
||||
* @see Chance16I()
|
||||
* @param a The nominator of the fraction
|
||||
* @param b The denominator of the fraction
|
||||
* @return True with (a/b) probability
|
||||
*/
|
||||
#ifdef RANDOM_DEBUG
|
||||
#define Chance16(a, b) Chance16I(a, b, DoRandom(__LINE__, __FILE__))
|
||||
#else
|
||||
static inline bool Chance16(const uint a, const uint b)
|
||||
{
|
||||
return Chance16I(a, b, Random());
|
||||
}
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
/**
|
||||
* Flips a coin with a given probability and saves the randomize-number in a variable.
|
||||
*
|
||||
* This function uses the same parameters as Chance16. The third parameter
|
||||
* must be a variable the randomize-number from Random() is saved in.
|
||||
*
|
||||
* The low 16 bits of r will already be used and can therefore not be passed to
|
||||
* Chance16I. One can only send the high 16 bits to Chance16I.
|
||||
*
|
||||
* @see Chance16I()
|
||||
* @param a The numerator of the fraction
|
||||
* @param b The denominator of the fraction
|
||||
* @param r The variable to save the randomize-number from Random()
|
||||
* @return True in (a/b) percent
|
||||
*/
|
||||
#ifdef RANDOM_DEBUG
|
||||
#define Chance16R(a, b, r) (r = DoRandom(__LINE__, __FILE__), Chance16I(a, b, r))
|
||||
#else
|
||||
static inline bool Chance16R(const uint a, const uint b, uint32 &r)
|
||||
{
|
||||
r = Random();
|
||||
return Chance16I(a, b, r);
|
||||
}
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
#endif /* RANDOM_FUNC_HPP */
|
||||
158
src/core/smallmap_type.hpp
Normal file
158
src/core/smallmap_type.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file smallmap_type.hpp Simple mapping class targeted for small sets of data. Stored data shall be POD ("Plain Old Data")! */
|
||||
|
||||
#ifndef SMALLMAP_TYPE_HPP
|
||||
#define SMALLMAP_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include "sort_func.hpp"
|
||||
|
||||
/**
|
||||
* Simple pair of data. Both types have to be POD ("Plain Old Data")!
|
||||
* @tparam T Key type.
|
||||
* @tparam U Value type.
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
struct SmallPair {
|
||||
T first;
|
||||
U second;
|
||||
|
||||
/** Initializes this Pair with data */
|
||||
inline SmallPair(const T &first, const U &second) : first(first), second(second) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of simple mapping class. Both types have to be POD ("Plain Old Data")!
|
||||
* It has inherited accessors from SmallVector().
|
||||
* @tparam T Key type.
|
||||
* @tparam U Value type.
|
||||
* @tparam S Unit of allocation.
|
||||
*
|
||||
* @see SmallVector
|
||||
*/
|
||||
template <typename T, typename U, uint S = 16>
|
||||
struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
typedef ::SmallPair<T, U> Pair;
|
||||
typedef Pair *iterator;
|
||||
typedef const Pair *const_iterator;
|
||||
|
||||
/** Creates new SmallMap. Data are initialized in SmallVector constructor */
|
||||
inline SmallMap() { }
|
||||
/** Data are freed in SmallVector destructor */
|
||||
inline ~SmallMap() { }
|
||||
|
||||
/**
|
||||
* Finds given key in this map
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline const Pair *Find(const T &key) const
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) return &this->data[i];
|
||||
}
|
||||
return this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds given key in this map
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline Pair *Find(const T &key)
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) return &this->data[i];
|
||||
}
|
||||
return this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key) const
|
||||
{
|
||||
return this->Find(key) != this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given pair from this map
|
||||
* @param pair pair to remove
|
||||
* @note it has to be pointer to pair in this map. It is overwritten by the last item.
|
||||
*/
|
||||
inline void Erase(Pair *pair)
|
||||
{
|
||||
assert(pair >= this->Begin() && pair < this->End());
|
||||
*pair = this->data[--this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given key from this map
|
||||
* @param key key to remove
|
||||
* @return true iff the key was found
|
||||
* @note last item is moved to its place, so don't increase your iterator if true is returned!
|
||||
*/
|
||||
inline bool Erase(const T &key)
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) {
|
||||
this->data[i] = this->data[--this->items];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new item to this map.
|
||||
* @param key key
|
||||
* @param data data
|
||||
* @return true iff the key wasn't already present
|
||||
*/
|
||||
inline bool Insert(const T &key, const U &data)
|
||||
{
|
||||
if (this->Contains(key)) return false;
|
||||
Pair *n = this->Append();
|
||||
n->first = key;
|
||||
n->second = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data belonging to this key
|
||||
* @param key key
|
||||
* @return data belonging to this key
|
||||
* @note if this key wasn't present, new entry is created
|
||||
*/
|
||||
inline U &operator[](const T &key)
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) return this->data[i].second;
|
||||
}
|
||||
Pair *n = this->Append();
|
||||
n->first = key;
|
||||
return n->second;
|
||||
}
|
||||
|
||||
inline void SortByKey()
|
||||
{
|
||||
QSortT(this->Begin(), this->items, KeySorter);
|
||||
}
|
||||
|
||||
static int CDECL KeySorter(const Pair *a, const Pair *b)
|
||||
{
|
||||
return a->first - b->first;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SMALLMAP_TYPE_HPP */
|
||||
322
src/core/smallmatrix_type.hpp
Normal file
322
src/core/smallmatrix_type.hpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file smallmatrix_type.hpp Simple matrix class that allows allocating an item without the need to copy this->data needlessly. */
|
||||
|
||||
#ifndef SMALLMATRIX_TYPE_HPP
|
||||
#define SMALLMATRIX_TYPE_HPP
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
|
||||
/**
|
||||
* Simple matrix template class.
|
||||
*
|
||||
* Allocating a matrix in one piece reduces overhead in allocations compared
|
||||
* with allocating a vector of vectors and saves some pointer dereferencing.
|
||||
* However, you can only get rectangular matrixes like this and if you're
|
||||
* changing their height very often performance will probably be worse than
|
||||
* with a vector of vectors, due to more frequent copying of memory blocks.
|
||||
*
|
||||
* No iterators are provided as iterating the columns would require persistent
|
||||
* column objects. Those do not exist. Providing iterators with transient
|
||||
* column objects would tie each iterator to a column object, thus replacing
|
||||
* previously retrieved columns when iterating and defeating the point of
|
||||
* iteration.
|
||||
*
|
||||
* It's expected that the items don't need to be constructed or deleted by the
|
||||
* container. Only memory allocation and deallocation is performed. This is the
|
||||
* same for all openttd "SmallContainer" classes.
|
||||
*
|
||||
* @tparam T The type of the items stored
|
||||
*/
|
||||
template <typename T>
|
||||
class SmallMatrix {
|
||||
protected:
|
||||
T *data; ///< The pointer to the first item
|
||||
uint width; ///< Number of items over first axis
|
||||
uint height; ///< Number of items over second axis
|
||||
uint capacity; ///< The available space for storing items
|
||||
|
||||
public:
|
||||
|
||||
SmallMatrix() : data(NULL), width(0), height(0), capacity(0) {}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param other The other matrix to copy.
|
||||
*/
|
||||
SmallMatrix(const SmallMatrix &other) : data(NULL), width(0), height(0), capacity(0)
|
||||
{
|
||||
this->Assign(other);
|
||||
}
|
||||
|
||||
~SmallMatrix()
|
||||
{
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assignment.
|
||||
* @param other The other matrix to assign.
|
||||
*/
|
||||
SmallMatrix &operator=(const SmallMatrix &other)
|
||||
{
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items from other vector.
|
||||
*/
|
||||
inline void Assign(const SmallMatrix &other)
|
||||
{
|
||||
if (&other == this) return;
|
||||
|
||||
this->height = other.Height();
|
||||
this->width = other.Width();
|
||||
uint num_items = this->width * this->height;
|
||||
if (num_items > this->capacity) {
|
||||
this->capacity = num_items;
|
||||
free(this->data);
|
||||
this->data = MallocT<T>(num_items);
|
||||
MemCpyT(this->data, other[0], num_items);
|
||||
} else if (num_items > 0) {
|
||||
MemCpyT(this->data, other[0], num_items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all rows from the matrix.
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
/* In fact we just reset the width avoiding the need to
|
||||
* probably reallocate the same amount of memory the matrix was
|
||||
* previously using. */
|
||||
this->width = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list and free allocated memory.
|
||||
*/
|
||||
inline void Reset()
|
||||
{
|
||||
this->height = 0;
|
||||
this->width = 0;
|
||||
this->capacity = 0;
|
||||
free(this->data);
|
||||
this->data = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the matrix down to the smallest possible size.
|
||||
*/
|
||||
inline void Compact()
|
||||
{
|
||||
uint capacity = this->height * this->width;
|
||||
if (capacity >= this->capacity) return;
|
||||
this->capacity = capacity;
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a column, replacing it with the last one.
|
||||
* @param x Position of the column.
|
||||
*/
|
||||
void EraseColumn(uint x)
|
||||
{
|
||||
if (x < --this->width) {
|
||||
MemCpyT<T>(this->data + x * this->height,
|
||||
this->data + this->width * this->height,
|
||||
this->height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove columns from the matrix while preserving the order of other columns.
|
||||
* @param x First column to remove.
|
||||
* @param count Number of consecutive columns to remove.
|
||||
*/
|
||||
void EraseColumnPreservingOrder(uint x, uint count = 1)
|
||||
{
|
||||
if (count == 0) return;
|
||||
assert(x < this->width);
|
||||
assert(x + count <= this->width);
|
||||
this->width -= count;
|
||||
uint to_move = (this->width - x) * this->height;
|
||||
if (to_move > 0) {
|
||||
MemMoveT(this->data + x * this->height,
|
||||
this->data + (x + count) * this->height, to_move);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a row, replacing it with the last one.
|
||||
* @param y Position of the row.
|
||||
*/
|
||||
void EraseRow(uint y)
|
||||
{
|
||||
if (y < this->height - 1) {
|
||||
for (uint x = 0; x < this->width; ++x) {
|
||||
this->data[x * this->height + y] =
|
||||
this->data[(x + 1) * this->height - 1];
|
||||
}
|
||||
}
|
||||
this->Resize(this->width, this->height - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove columns from the matrix while preserving the order of other columns.
|
||||
* @param y First column to remove.
|
||||
* @param count Number of consecutive columns to remove.
|
||||
*/
|
||||
void EraseRowPreservingOrder(uint y, uint count = 1)
|
||||
{
|
||||
if (this->height > count + y) {
|
||||
for (uint x = 0; x < this->width; ++x) {
|
||||
MemMoveT(this->data + x * this->height + y,
|
||||
this->data + x * this->height + y + count,
|
||||
this->height - count - y);
|
||||
}
|
||||
}
|
||||
this->Resize(this->width, this->height - count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append rows.
|
||||
* @param to_add Number of rows to append.
|
||||
*/
|
||||
inline void AppendRow(uint to_add = 1)
|
||||
{
|
||||
this->Resize(this->width, to_add + this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append rows.
|
||||
* @param to_add Number of rows to append.
|
||||
*/
|
||||
inline void AppendColumn(uint to_add = 1)
|
||||
{
|
||||
this->Resize(to_add + this->width, this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size to a specific width and height, preserving item positions
|
||||
* as far as possible in the process.
|
||||
* @param new_width Target width.
|
||||
* @param new_height Target height.
|
||||
*/
|
||||
inline void Resize(uint new_width, uint new_height)
|
||||
{
|
||||
uint new_capacity = new_width * new_height;
|
||||
T *new_data = NULL;
|
||||
void (*copy)(T *dest, const T *src, size_t count) = NULL;
|
||||
if (new_capacity > this->capacity) {
|
||||
/* If the data doesn't fit into current capacity, resize and copy ... */
|
||||
new_data = MallocT<T>(new_capacity);
|
||||
copy = &MemCpyT<T>;
|
||||
} else {
|
||||
/* ... otherwise just move the columns around, if necessary. */
|
||||
new_data = this->data;
|
||||
copy = &MemMoveT<T>;
|
||||
}
|
||||
if (this->height != new_height || new_data != this->data) {
|
||||
if (this->height > 0) {
|
||||
if (new_height > this->height) {
|
||||
/* If matrix is growing, copy from the back to avoid
|
||||
* overwriting uncopied data. */
|
||||
for (uint x = this->width; x > 0; --x) {
|
||||
if (x * new_height > new_capacity) continue;
|
||||
(*copy)(new_data + (x - 1) * new_height,
|
||||
this->data + (x - 1) * this->height,
|
||||
min(this->height, new_height));
|
||||
}
|
||||
} else {
|
||||
/* If matrix is shrinking copy from the front. */
|
||||
for (uint x = 0; x < this->width; ++x) {
|
||||
if ((x + 1) * new_height > new_capacity) break;
|
||||
(*copy)(new_data + x * new_height,
|
||||
this->data + x * this->height,
|
||||
min(this->height, new_height));
|
||||
}
|
||||
}
|
||||
}
|
||||
this->height = new_height;
|
||||
if (new_data != this->data) {
|
||||
free(this->data);
|
||||
this->data = new_data;
|
||||
this->capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
this->width = new_width;
|
||||
}
|
||||
|
||||
inline uint Height() const
|
||||
{
|
||||
return this->height;
|
||||
}
|
||||
|
||||
inline uint Width() const
|
||||
{
|
||||
return this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item x/y (const).
|
||||
*
|
||||
* @param x X-position of the item.
|
||||
* @param y Y-position of the item.
|
||||
* @return Item at specified position.
|
||||
*/
|
||||
inline const T &Get(uint x, uint y) const
|
||||
{
|
||||
assert(x < this->width && y < this->height);
|
||||
return this->data[x * this->height + y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item x/y.
|
||||
*
|
||||
* @param x X-position of the item.
|
||||
* @param y Y-position of the item.
|
||||
* @return Item at specified position.
|
||||
*/
|
||||
inline T &Get(uint x, uint y)
|
||||
{
|
||||
assert(x < this->width && y < this->height);
|
||||
return this->data[x * this->height + y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column "number" (const)
|
||||
*
|
||||
* @param x Position of the column.
|
||||
* @return Column at "number".
|
||||
*/
|
||||
inline const T *operator[](uint x) const
|
||||
{
|
||||
assert(x < this->width);
|
||||
return this->data + x * this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column "number" (const)
|
||||
*
|
||||
* @param x Position of the column.
|
||||
* @return Column at "number".
|
||||
*/
|
||||
inline T *operator[](uint x)
|
||||
{
|
||||
assert(x < this->width);
|
||||
return this->data + x * this->height;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SMALLMATRIX_TYPE_HPP */
|
||||
290
src/core/smallstack_type.hpp
Normal file
290
src/core/smallstack_type.hpp
Normal file
@@ -0,0 +1,290 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file smallstack_type.hpp Minimal stack that uses a pool to avoid pointers and doesn't allocate any heap memory if there is only one valid item. */
|
||||
|
||||
#ifndef SMALLSTACK_TYPE_HPP
|
||||
#define SMALLSTACK_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include "../thread/thread.h"
|
||||
|
||||
/**
|
||||
* A simplified pool which stores values instead of pointers and doesn't
|
||||
* redefine operator new/delete. It also never zeroes memory and always reuses
|
||||
* it.
|
||||
*/
|
||||
template<typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
|
||||
class SimplePool {
|
||||
public:
|
||||
inline SimplePool() : first_unused(0), first_free(0), mutex(ThreadMutex::New()) {}
|
||||
inline ~SimplePool() { delete this->mutex; }
|
||||
|
||||
/**
|
||||
* Get the mutex. We don't lock the mutex in the pool methods as the
|
||||
* SmallStack isn't necessarily in a consistent state after each method.
|
||||
* @return Mutex.
|
||||
*/
|
||||
inline ThreadMutex *GetMutex() { return this->mutex; }
|
||||
|
||||
/**
|
||||
* Get the item at position index.
|
||||
* @return Item at index.
|
||||
*/
|
||||
inline Titem &Get(Tindex index) { return this->data[index]; }
|
||||
|
||||
/**
|
||||
* Create a new item and return its index.
|
||||
* @return Index of new item.
|
||||
*/
|
||||
inline Tindex Create()
|
||||
{
|
||||
Tindex index = this->FindFirstFree();
|
||||
if (index < Tmax_size) {
|
||||
this->data[index].valid = true;
|
||||
this->first_free = index + 1;
|
||||
this->first_unused = max(this->first_unused, this->first_free);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy (or rather invalidate) the item at the given index.
|
||||
* @param index Index of item to be destroyed.
|
||||
*/
|
||||
inline void Destroy(Tindex index)
|
||||
{
|
||||
this->data[index].valid = false;
|
||||
this->first_free = min(this->first_free, index);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline Tindex FindFirstFree()
|
||||
{
|
||||
Tindex index = this->first_free;
|
||||
for (; index < this->first_unused; index++) {
|
||||
if (!this->data[index].valid) return index;
|
||||
}
|
||||
|
||||
if (index >= this->data.Length() && index < Tmax_size) {
|
||||
this->data.Resize(index + 1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
struct SimplePoolPoolItem : public Titem {
|
||||
bool valid;
|
||||
};
|
||||
|
||||
Tindex first_unused;
|
||||
Tindex first_free;
|
||||
|
||||
ThreadMutex *mutex;
|
||||
SmallVector<SimplePoolPoolItem, Tgrowth_step> data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for SmallStack. We cannot add this into SmallStack itself as
|
||||
* certain compilers don't like it.
|
||||
*/
|
||||
template <typename Titem, typename Tindex>
|
||||
struct SmallStackItem {
|
||||
Tindex next; ///< Pool index of next item.
|
||||
Titem value; ///< Value of current item.
|
||||
|
||||
/**
|
||||
* Create a new item.
|
||||
* @param value Value of the item.
|
||||
* @param next Next item in the stack.
|
||||
*/
|
||||
inline SmallStackItem(const Titem &value, Tindex next) :
|
||||
next(next), value(value) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Minimal stack that uses a pool to avoid pointers. It has some peculiar
|
||||
* properties that make it useful for passing around lists of IDs but not much
|
||||
* else:
|
||||
* 1. It always includes an invalid item as bottom.
|
||||
* 2. It doesn't have a deep copy operation but uses smart pointers instead.
|
||||
* Every copy is thus implicitly shared.
|
||||
* 3. Its items are immutable.
|
||||
* 4. Due to 2. and 3. memory management can be done by "branch counting".
|
||||
* Whenever you copy a smallstack, the first item on the heap increases its
|
||||
* branch_count, signifying that there are multiple items "in front" of it.
|
||||
* When deleting a stack items are deleted up to the point where
|
||||
* branch_count > 0.
|
||||
* 5. You can choose your own index type, so that you can align it with your
|
||||
* value type. E.G. value types of 16 bits length like to be combined with
|
||||
* index types of the same length.
|
||||
* 6. All accesses to the underlying pool are guarded by a mutex and atomic in
|
||||
* the sense that the mutex stays locked until the pool has reacquired a
|
||||
* consistent state. This means that even though a common data structure is
|
||||
* used the SmallStack is still reentrant.
|
||||
* @tparam Titem Value type to be used.
|
||||
* @tparam Tindex Index type to use for the pool.
|
||||
* @tparam Tinvalid Invalid item to keep at the bottom of each stack.
|
||||
* @tparam Tgrowth_step Growth step for pool.
|
||||
* @tparam Tmax_size Maximum size for pool.
|
||||
*/
|
||||
template <typename Titem, typename Tindex, Titem Tinvalid, Tindex Tgrowth_step, Tindex Tmax_size>
|
||||
class SmallStack : public SmallStackItem<Titem, Tindex> {
|
||||
public:
|
||||
|
||||
typedef SmallStackItem<Titem, Tindex> Item;
|
||||
|
||||
/**
|
||||
* SmallStack item that can be kept in a pool.
|
||||
*/
|
||||
struct PooledSmallStack : public Item {
|
||||
Tindex branch_count; ///< Number of branches in the tree structure this item is parent of
|
||||
};
|
||||
|
||||
typedef SimplePool<PooledSmallStack, Tindex, Tgrowth_step, Tmax_size> SmallStackPool;
|
||||
|
||||
/**
|
||||
* Constructor for a stack with one or two items in it.
|
||||
* @param value Initial item. If not missing or Tinvalid there will be Tinvalid below it.
|
||||
*/
|
||||
inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
|
||||
|
||||
/**
|
||||
* Remove the head of stack and all other items members that are unique to it.
|
||||
*/
|
||||
inline ~SmallStack()
|
||||
{
|
||||
/* Pop() locks the mutex and after each pop the pool is consistent.*/
|
||||
while (this->next != Tmax_size) this->Pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shallow copy the stack, marking the first item as branched.
|
||||
* @param other Stack to copy from
|
||||
*/
|
||||
inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
|
||||
|
||||
/**
|
||||
* Shallow copy the stack, marking the first item as branched.
|
||||
* @param other Stack to copy from
|
||||
* @return This smallstack.
|
||||
*/
|
||||
inline SmallStack &operator=(const SmallStack &other)
|
||||
{
|
||||
if (this == &other) return *this;
|
||||
while (this->next != Tmax_size) this->Pop();
|
||||
this->next = other.next;
|
||||
this->value = other.value;
|
||||
/* Deleting and branching are independent operations, so it's fine to
|
||||
* acquire separate locks for them. */
|
||||
this->Branch();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a new item onto the stack if there is still space in the
|
||||
* underlying pool. Otherwise the topmost item's value gets overwritten.
|
||||
* @param item Item to be pushed.
|
||||
*/
|
||||
inline void Push(const Titem &item)
|
||||
{
|
||||
if (this->value != Tinvalid) {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
Tindex new_item = SmallStack::GetPool().Create();
|
||||
if (new_item != Tmax_size) {
|
||||
PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
|
||||
pushed.value = this->value;
|
||||
pushed.next = this->next;
|
||||
pushed.branch_count = 0;
|
||||
this->next = new_item;
|
||||
}
|
||||
}
|
||||
this->value = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop an item from the stack.
|
||||
* @return Current top of stack.
|
||||
*/
|
||||
inline Titem Pop()
|
||||
{
|
||||
Titem ret = this->value;
|
||||
if (this->next == Tmax_size) {
|
||||
this->value = Tinvalid;
|
||||
} else {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
|
||||
this->value = popped.value;
|
||||
if (popped.branch_count == 0) {
|
||||
SmallStack::GetPool().Destroy(this->next);
|
||||
} else {
|
||||
--popped.branch_count;
|
||||
/* We can't use Branch() here as we already have the mutex.*/
|
||||
if (popped.next != Tmax_size) {
|
||||
++(SmallStack::GetPool().Get(popped.next).branch_count);
|
||||
}
|
||||
}
|
||||
/* Accessing popped here is no problem as the pool will only set
|
||||
* the validity flag, not actually delete the item, on Destroy().
|
||||
* It's impossible for another thread to acquire the same item in
|
||||
* the mean time because of the mutex. */
|
||||
this->next = popped.next;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the stack is empty.
|
||||
* @return If the stack is empty.
|
||||
*/
|
||||
inline bool IsEmpty() const
|
||||
{
|
||||
return this->value == Tinvalid && this->next == Tmax_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given item is contained in the stack.
|
||||
* @param item Item to look for.
|
||||
* @return If the item is in the stack.
|
||||
*/
|
||||
inline bool Contains(const Titem &item) const
|
||||
{
|
||||
if (item == Tinvalid || item == this->value) return true;
|
||||
if (this->next != Tmax_size) {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
const SmallStack *in_list = this;
|
||||
do {
|
||||
in_list = static_cast<const SmallStack *>(
|
||||
static_cast<const Item *>(&SmallStack::GetPool().Get(in_list->next)));
|
||||
if (in_list->value == item) return true;
|
||||
} while (in_list->next != Tmax_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
static SmallStackPool &GetPool()
|
||||
{
|
||||
static SmallStackPool pool;
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a branch in the pool if necessary.
|
||||
*/
|
||||
inline void Branch()
|
||||
{
|
||||
if (this->next != Tmax_size) {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
++(SmallStack::GetPool().Get(this->next).branch_count);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
451
src/core/smallvec_type.hpp
Normal file
451
src/core/smallvec_type.hpp
Normal file
@@ -0,0 +1,451 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file smallvec_type.hpp Simple vector class that allows allocating an item without the need to copy this->data needlessly. */
|
||||
|
||||
#ifndef SMALLVEC_TYPE_HPP
|
||||
#define SMALLVEC_TYPE_HPP
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
|
||||
/**
|
||||
* Simple vector template class.
|
||||
*
|
||||
* @note There are no asserts in the class so you have
|
||||
* to care about that you grab an item which is
|
||||
* inside the list.
|
||||
*
|
||||
* @tparam T The type of the items stored
|
||||
* @tparam S The steps of allocation
|
||||
*/
|
||||
template <typename T, uint S>
|
||||
class SmallVector {
|
||||
protected:
|
||||
T *data; ///< The pointer to the first item
|
||||
uint items; ///< The number of items stored
|
||||
uint capacity; ///< The available space for storing items
|
||||
|
||||
public:
|
||||
SmallVector() : data(NULL), items(0), capacity(0) { }
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param other The other vector to copy.
|
||||
*/
|
||||
SmallVector(const SmallVector &other) : data(NULL), items(0), capacity(0)
|
||||
{
|
||||
this->Assign(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic copy constructor.
|
||||
* @param other The other vector to copy.
|
||||
*/
|
||||
template <uint X>
|
||||
SmallVector(const SmallVector<T, X> &other) : data(NULL), items(0), capacity(0)
|
||||
{
|
||||
this->Assign(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assignment.
|
||||
* @param other The other vector to assign.
|
||||
*/
|
||||
SmallVector &operator=(const SmallVector &other)
|
||||
{
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic assignment.
|
||||
* @param other The other vector to assign.
|
||||
*/
|
||||
template <uint X>
|
||||
SmallVector &operator=(const SmallVector<T, X> &other)
|
||||
{
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~SmallVector()
|
||||
{
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items from other vector.
|
||||
*/
|
||||
template <uint X>
|
||||
inline void Assign(const SmallVector<T, X> &other)
|
||||
{
|
||||
if ((const void *)&other == (void *)this) return;
|
||||
|
||||
this->Clear();
|
||||
if (other.Length() > 0) MemCpyT<T>(this->Append(other.Length()), other.Begin(), other.Length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list.
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
/* In fact we just reset the item counter avoiding the need to
|
||||
* probably reallocate the same amount of memory the list was
|
||||
* previously using. */
|
||||
this->items = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list and free allocated memory.
|
||||
*/
|
||||
inline void Reset()
|
||||
{
|
||||
this->items = 0;
|
||||
this->capacity = 0;
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the list down to the smallest block size boundary.
|
||||
*/
|
||||
inline void Compact()
|
||||
{
|
||||
uint capacity = Align(this->items, S);
|
||||
if (capacity >= this->capacity) return;
|
||||
|
||||
this->capacity = capacity;
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an item and return it.
|
||||
* @param to_add the number of items to append
|
||||
* @return pointer to newly allocated item
|
||||
*/
|
||||
inline T *Append(uint to_add = 1)
|
||||
{
|
||||
uint begin = this->items;
|
||||
this->items += to_add;
|
||||
|
||||
if (this->items > this->capacity) {
|
||||
this->capacity = Align(this->items, S);
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
return &this->data[begin];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the vector, effectively truncating items from the end or appending uninitialised ones.
|
||||
* @param num_items Target size.
|
||||
*/
|
||||
inline void Resize(uint num_items)
|
||||
{
|
||||
this->items = num_items;
|
||||
|
||||
if (this->items > this->capacity) {
|
||||
this->capacity = Align(this->items, S);
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new item at a specific position into the vector, moving all following items.
|
||||
* @param item Position at which the new item should be inserted
|
||||
* @return pointer to the new item
|
||||
*/
|
||||
inline T *Insert(T *item)
|
||||
{
|
||||
assert(item >= this->Begin() && item <= this->End());
|
||||
|
||||
size_t to_move = this->End() - item;
|
||||
size_t start = item - this->Begin();
|
||||
|
||||
this->Append();
|
||||
if (to_move > 0) MemMoveT(this->Begin() + start + 1, this->Begin() + start, to_move);
|
||||
return this->Begin() + start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first occurrence of an item.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to search for
|
||||
* @return The position of the item, or End() when not present
|
||||
*/
|
||||
inline const T *Find(const T &item) const
|
||||
{
|
||||
const T *pos = this->Begin();
|
||||
const T *end = this->End();
|
||||
while (pos != end && *pos != item) pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first occurrence of an item.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to search for
|
||||
* @return The position of the item, or End() when not present
|
||||
*/
|
||||
inline T *Find(const T &item)
|
||||
{
|
||||
T *pos = this->Begin();
|
||||
const T *end = this->End();
|
||||
while (pos != end && *pos != item) pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first occurrence of an item.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to search for
|
||||
* @return The position of the item, or -1 when not present
|
||||
*/
|
||||
inline int FindIndex(const T &item) const
|
||||
{
|
||||
int index = 0;
|
||||
const T *pos = this->Begin();
|
||||
const T *end = this->End();
|
||||
while (pos != end && *pos != item) {
|
||||
pos++;
|
||||
index++;
|
||||
}
|
||||
return pos == end ? -1 : index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a item is present in the vector.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to test for
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &item) const
|
||||
{
|
||||
return this->Find(item) != this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given item from this vector
|
||||
* @param item item to remove
|
||||
* @note it has to be pointer to item in this map. It is overwritten by the last item.
|
||||
*/
|
||||
inline void Erase(T *item)
|
||||
{
|
||||
assert(item >= this->Begin() && item < this->End());
|
||||
*item = this->data[--this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove items from the vector while preserving the order of other items.
|
||||
* @param pos First item to remove.
|
||||
* @param count Number of consecutive items to remove.
|
||||
*/
|
||||
void ErasePreservingOrder(uint pos, uint count = 1)
|
||||
{
|
||||
ErasePreservingOrder(this->data + pos, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove items from the vector while preserving the order of other items.
|
||||
* @param item First item to remove.
|
||||
* @param count Number of consecutive items to remove.
|
||||
*/
|
||||
inline void ErasePreservingOrder(T *item, uint count = 1)
|
||||
{
|
||||
if (count == 0) return;
|
||||
assert(item >= this->Begin());
|
||||
assert(item + count <= this->End());
|
||||
|
||||
this->items -= count;
|
||||
ptrdiff_t to_move = this->End() - item;
|
||||
if (to_move > 0) MemMoveT(item, item + count, to_move);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a item is present in the vector, and appends it to the end if not.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to test for
|
||||
* @return true iff the item is was already present
|
||||
*/
|
||||
inline bool Include(const T &item)
|
||||
{
|
||||
bool is_member = this->Contains(item);
|
||||
if (!is_member) *this->Append() = item;
|
||||
return is_member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of items in the list.
|
||||
*
|
||||
* @return The number of items in the list.
|
||||
*/
|
||||
inline uint Length() const
|
||||
{
|
||||
return this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to the first item (const)
|
||||
*
|
||||
* @return the pointer to the first item
|
||||
*/
|
||||
inline const T *Begin() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to the first item
|
||||
*
|
||||
* @return the pointer to the first item
|
||||
*/
|
||||
inline T *Begin()
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer behind the last valid item (const)
|
||||
*
|
||||
* @return the pointer behind the last valid item
|
||||
*/
|
||||
inline const T *End() const
|
||||
{
|
||||
return &this->data[this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer behind the last valid item
|
||||
*
|
||||
* @return the pointer behind the last valid item
|
||||
*/
|
||||
inline T *End()
|
||||
{
|
||||
return &this->data[this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to item "number" (const)
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the pointer to the item
|
||||
*/
|
||||
inline const T *Get(uint index) const
|
||||
{
|
||||
/* Allow access to the 'first invalid' item */
|
||||
assert(index <= this->items);
|
||||
return &this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to item "number"
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the pointer to the item
|
||||
*/
|
||||
inline T *Get(uint index)
|
||||
{
|
||||
/* Allow access to the 'first invalid' item */
|
||||
assert(index <= this->items);
|
||||
return &this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item "number" (const)
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the item
|
||||
*/
|
||||
inline const T &operator[](uint index) const
|
||||
{
|
||||
assert(index < this->items);
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item "number"
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the item
|
||||
*/
|
||||
inline T &operator[](uint index)
|
||||
{
|
||||
assert(index < this->items);
|
||||
return this->data[index];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Simple vector template class, with automatic free.
|
||||
*
|
||||
* @note There are no asserts in the class so you have
|
||||
* to care about that you grab an item which is
|
||||
* inside the list.
|
||||
*
|
||||
* @param T The type of the items stored, must be a pointer
|
||||
* @param S The steps of allocation
|
||||
*/
|
||||
template <typename T, uint S>
|
||||
class AutoFreeSmallVector : public SmallVector<T, S> {
|
||||
public:
|
||||
~AutoFreeSmallVector()
|
||||
{
|
||||
this->Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list.
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
free(this->data[i]);
|
||||
}
|
||||
|
||||
this->items = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple vector template class, with automatic delete.
|
||||
*
|
||||
* @note There are no asserts in the class so you have
|
||||
* to care about that you grab an item which is
|
||||
* inside the list.
|
||||
*
|
||||
* @param T The type of the items stored, must be a pointer
|
||||
* @param S The steps of allocation
|
||||
*/
|
||||
template <typename T, uint S>
|
||||
class AutoDeleteSmallVector : public SmallVector<T, S> {
|
||||
public:
|
||||
~AutoDeleteSmallVector()
|
||||
{
|
||||
this->Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list.
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
delete this->data[i];
|
||||
}
|
||||
|
||||
this->items = 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef AutoFreeSmallVector<char*, 4> StringList; ///< Type for a list of strings.
|
||||
|
||||
#endif /* SMALLVEC_TYPE_HPP */
|
||||
89
src/core/sort_func.hpp
Normal file
89
src/core/sort_func.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file sort_func.hpp Functions related to sorting operations. */
|
||||
|
||||
#ifndef SORT_FUNC_HPP
|
||||
#define SORT_FUNC_HPP
|
||||
|
||||
#include "mem_func.hpp"
|
||||
|
||||
/**
|
||||
* Type safe qsort()
|
||||
*
|
||||
* @note Use this sort for irregular sorted data.
|
||||
*
|
||||
* @param base Pointer to the first element of the array to be sorted.
|
||||
* @param num Number of elements in the array pointed by base.
|
||||
* @param comparator Function that compares two elements.
|
||||
* @param desc Sort descending.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void QSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
{
|
||||
if (num < 2) return;
|
||||
|
||||
qsort(base, num, sizeof(T), (int (CDECL *)(const void *, const void *))comparator);
|
||||
|
||||
if (desc) MemReverseT(base, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe Gnome Sort.
|
||||
*
|
||||
* This is a slightly modified Gnome search. The basic
|
||||
* Gnome search tries to sort already sorted list parts.
|
||||
* The modification skips these.
|
||||
*
|
||||
* @note Use this sort for presorted / regular sorted data.
|
||||
*
|
||||
* @param base Pointer to the first element of the array to be sorted.
|
||||
* @param num Number of elements in the array pointed by base.
|
||||
* @param comparator Function that compares two elements.
|
||||
* @param desc Sort descending.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void GSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
{
|
||||
if (num < 2) return;
|
||||
|
||||
assert(base != NULL);
|
||||
assert(comparator != NULL);
|
||||
|
||||
T *a = base;
|
||||
T *b = base + 1;
|
||||
uint offset = 0;
|
||||
|
||||
while (num > 1) {
|
||||
const int diff = comparator(a, b);
|
||||
if ((!desc && diff <= 0) || (desc && diff >= 0)) {
|
||||
if (offset != 0) {
|
||||
/* Jump back to the last direction switch point */
|
||||
a += offset;
|
||||
b += offset;
|
||||
offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
a++;
|
||||
b++;
|
||||
num--;
|
||||
} else {
|
||||
Swap(*a, *b);
|
||||
|
||||
if (a == base) continue;
|
||||
|
||||
a--;
|
||||
b--;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SORT_FUNC_HPP */
|
||||
29
src/core/string_compare_type.hpp
Normal file
29
src/core/string_compare_type.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file string_compare_type.hpp Comparator class for "const char *" so it can be used as a key for std::map */
|
||||
|
||||
#ifndef STRING_COMPARE_TYPE_HPP
|
||||
#define STRING_COMPARE_TYPE_HPP
|
||||
|
||||
/** Comparator for strings. */
|
||||
struct StringCompare {
|
||||
/**
|
||||
* Compare two strings.
|
||||
* @param a The first string.
|
||||
* @param b The second string.
|
||||
* @return True is the first string is deemed "lower" than the second string.
|
||||
*/
|
||||
bool operator () (const char *a, const char *b) const
|
||||
{
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* STRING_COMPARE_TYPE_HPP */
|
||||
Reference in New Issue
Block a user