rubidium@6751: /* $Id$ */ richk@6739: richk@6739: /** @file FSMblockmap.h Definition of FSMblockmap class for use in state machines*/ richk@6739: richk@6739: #ifndef FSMBLOCKMAP_H richk@6739: #define FSMBLOCKMAP_H richk@6739: richk@6739: #include "stdafx.h" richk@6739: rubidium@6751: uint64 inline GetBlockAsBits(byte blocknumber) richk@6739: { richk@6739: if (blocknumber == 0) return 0ULL; richk@6739: if (blocknumber > 63) blocknumber -= 64; richk@6739: uint64 result = 1ULL << blocknumber; richk@6739: return result; richk@6739: } richk@6739: richk@6739: /** richk@6739: * This class provides functions and internal storage for blockmaps used in Finite State Machine richk@6739: * richk@6739: */ richk@6739: struct FSMblockmap { rubidium@6758: public: rubidium@6758: void inline ResetAll() rubidium@6758: { rubidium@6783: blocks[0] = 0x0000000000000000ULL; rubidium@6783: blocks[1] = 0x0000000000000000ULL; rubidium@6758: }; richk@6739: richk@6782: void inline SetAll() richk@6782: { rubidium@6783: blocks[0] = 0xFFFFFFFFFFFFFFFFULL; rubidium@6783: blocks[1] = 0xFFFFFFFFFFFFFFFFULL; richk@6782: }; richk@6782: rubidium@6758: void Initialise(const byte *blocklist, int num_bytes) rubidium@6758: { rubidium@6758: ResetAll(); rubidium@6758: for (int i = 0; i < num_bytes; i++) { richk@6782: if (blocklist[i] == 0xFF) { richk@6782: SetAll(); richk@6782: break; richk@6782: } rubidium@6758: blocks[(blocklist[i] < 64) ? 0 : 1] |= GetBlockAsBits(blocklist[i]); richk@6739: } rubidium@6758: } richk@6739: rubidium@6758: uint64 inline GetLower() const rubidium@6758: { rubidium@6758: return blocks[0]; rubidium@6758: } richk@6739: rubidium@6758: uint64 inline GetUpper() const rubidium@6758: { rubidium@6758: return blocks[1]; rubidium@6758: } richk@6739: richk@6819: void inline BlockCopy(const FSMblockmap *blockmap) richk@6819: { richk@6819: blocks[0] = blockmap->GetLower(); richk@6819: blocks[1] = blockmap->GetUpper(); richk@6819: } richk@6819: rubidium@6758: void inline ReserveBlocks(const FSMblockmap *blockmap) rubidium@6758: { rubidium@6758: /* OR with blockmap to reserve blocks */ rubidium@6758: blocks[0] |= blockmap->GetLower(); rubidium@6758: blocks[1] |= blockmap->GetUpper(); rubidium@6758: } richk@6739: rubidium@6758: void inline ReleaseBlocks(const FSMblockmap *blockmap) rubidium@6758: { rubidium@6758: /* AND with ones-complement to clear set bits in blockmap from block_lower and block_upper */ rubidium@6758: blocks[0] &= ~blockmap->GetLower(); rubidium@6758: blocks[1] &= ~blockmap->GetUpper(); rubidium@6758: } rubidium@6751: richk@6839: void inline ReleaseOnlyOwnedBlocks(const FSMblockmap *blockmap, const FSMblockmap *owned_blockmap) richk@6839: { richk@6839: /* AND with ones-complement to clear set bits in blockmap from block_lower and block_upper */ richk@6839: blocks[0] &= ~(blockmap->GetLower() & owned_blockmap->GetLower()); richk@6839: blocks[1] &= ~(blockmap->GetUpper() & owned_blockmap->GetUpper()); richk@6839: } richk@6839: richk@6805: void inline ReleaseLowerBlocks(const FSMblockmap *blockmap) richk@6805: { richk@6805: /* used to forget any existing terminal reservations */ richk@6805: blocks[0] &= ~blockmap->GetLower(); richk@6805: } richk@6805: richk@6845: void inline ReleaseUpperBlocks(const FSMblockmap *blockmap) richk@6845: { richk@6845: /* used to forget any normal movemnt reservations */ richk@6845: blocks[1] &= ~blockmap->GetUpper(); richk@6845: } richk@6845: rubidium@6758: bool inline BlocksAreFree(const FSMblockmap *blockmap) const rubidium@6758: { rubidium@6758: uint64 test_lower = blockmap->GetLower(); rubidium@6758: uint64 test_upper = blockmap->GetUpper(); rubidium@6758: rubidium@6758: if ((~blocks[0] & test_lower) != test_lower) return false; rubidium@6758: if ((~blocks[1] & test_upper) != test_upper) return false; rubidium@6758: rubidium@6758: return true; rubidium@6758: } rubidium@6758: richk@6810: bool inline CanReserveBlocks(const FSMblockmap *wantedblockmap, const FSMblockmap *targetblockmap) const richk@6805: { richk@6810: /* HasBlocks is a strict "have I got all the blocks? Yes/No". While useful in places richk@6810: * sometimes you want to ask "ive got some blocks. can I get the rest?" richk@6810: * This function does that. richk@6810: * The first assignment calculates which bits you need, but dont already have. richk@6810: * Then it tests whether the remaining bits are free in targetblockmap. richk@6810: * If they are, then return true. richk@6810: */ richk@6805: uint64 test_lower = (blocks[0] ^ wantedblockmap->GetLower()) & wantedblockmap->GetLower(); richk@6805: uint64 test_upper = (blocks[1] ^ wantedblockmap->GetUpper()) & wantedblockmap->GetUpper(); richk@6805: richk@6810: if ((~targetblockmap->GetLower() & test_lower) != test_lower) return false; richk@6810: if ((~targetblockmap->GetUpper() & test_upper) != test_upper) return false; richk@6805: richk@6805: return true; richk@6805: } richk@6805: rubidium@6758: bool inline HasBlocks(const FSMblockmap *blockmap) const rubidium@6758: { rubidium@6758: uint64 test_lower = blockmap->GetLower(); rubidium@6758: uint64 test_upper = blockmap->GetUpper(); rubidium@6758: rubidium@6758: if ((blocks[0] & test_lower) != test_lower) return false; rubidium@6758: if ((blocks[1] & test_upper) != test_upper) return false; rubidium@6758: rubidium@6758: return true; rubidium@6758: } rubidium@6758: rubidium@6758: bool inline HasBlock(byte blocknumber) const rubidium@6758: { rubidium@6758: FSMblockmap test_blockmap; rubidium@6758: test_blockmap.Initialise(&blocknumber, 1); rubidium@6758: return HasBlocks(&test_blockmap); rubidium@6758: } rubidium@6758: rubidium@6758: //bool inline HasBlock(byte blocknumber) rubidium@6758: //{ rubidium@6758: // uint64 test_block = GetBlockAsBits(blocknumber); rubidium@6758: // if (blocknumber < 64) return ((block_lower & test_block) == test_block); rubidium@6758: // return ((block_upper & test_block) == test_block); rubidium@6758: //} rubidium@6758: rubidium@6758: bool inline IsNotZero(void) const rubidium@6758: { rubidium@6758: return ((blocks[0] != 0) || (blocks[1] != 0)); rubidium@6758: } rubidium@6758: rubidium@6758: void PrintBlock(bool newline = true) const; rubidium@6758: rubidium@6758: /** rubidium@6758: * Needed for an ugly hack: rubidium@6758: * - vehicles and stations need to store fsmblocks, so they use FSMBlock as container rubidium@6758: * - this internals of the container should be protected, e.g. private (or protected) by C++ rubidium@6758: * - for saving/loading we need to pass pointer to objects rubidium@6758: * -> so *if* the pointer to the FSMBlock is the same as the pointer to the blocks array rubidium@6758: * encapsulated in the FSMBlock, we can just pass the FSMBlock as "offset". rubidium@6758: * Normally we would then just add the offset of the blocks variable within the class rubidium@6758: * but that is not possible because the variable is private. Furthermore we are not sure rubidium@6758: * that this works on all platforms, we need to check whether the offset is actually 0. rubidium@6758: * This cannot be done compile time, because the variable is private. So we need to write rubidium@6758: * a function that does actually check the offset runtime and call it somewhere where it rubidium@6758: * is always called but it should not be called often. rubidium@6758: */ rubidium@6758: static void AssertOnWrongBlockOffset(); rubidium@6758: rubidium@6758: private: rubidium@6758: uint64 blocks[2]; richk@6739: }; richk@6739: rubidium@6751: FSMblockmap* SetFSMSingleBlock(const byte *blocklist); richk@6739: richk@6739: #endif /* FSMBLOCKMAP_H */