Last active
June 10, 2025 18:31
-
-
Save kevyonan/b6a982a18fd96ae748548331efcd82ec to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * bitset.inc | |
| * | |
| * Copyright [2025] Nergal the Ashurian | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| * this software and associated documentation files (the "Software"), | |
| * to deal in the Software without restriction, | |
| * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, | |
| * subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
| * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. | |
| * | |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| * | |
| */ | |
| #if defined _bitset_included | |
| #endinput | |
| #endif | |
| #define _bitset_included | |
| #include <sourcemod> | |
| enum { | |
| INT_BIT_LEN = 32, | |
| INT_BIT_LEN_IDX = 5, | |
| }; | |
| stock int HighBitIndex(int a) { | |
| int bit_index = 1; | |
| for( int i = a >>> 1; i > 0; i >>>= 1 ) { | |
| bit_index++; | |
| } | |
| return bit_index - 1; | |
| } | |
| stock int PopCount(int x) { | |
| int count = 0; | |
| for( int i = x; i > 0; count++ ) { | |
| i &= (i - 1); | |
| } | |
| return count; | |
| } | |
| /// this assumes only ONE bit has been set in the entire bitset. | |
| /// as this will return on the first non-zero, highest bit it can find. | |
| stock int BitVecToBitIndex(const int[] bitvec, int len) { | |
| int bitidx = 0; | |
| for( int i=0; i < len; i++ ) { | |
| if( bitvec[i]==0 ) { | |
| bitidx += INT_BIT_LEN; | |
| continue; | |
| } | |
| bitidx += HighBitIndex(bitvec[i]); | |
| break; | |
| } | |
| return bitidx; | |
| } | |
| stock int BitIndexToBitPos(int bitidx) { | |
| return bitidx & (INT_BIT_LEN-1); /// modulos by bit-size of type | |
| } | |
| stock int BitIndexToSlot(int bitidx) { | |
| return bitidx >>> INT_BIT_LEN_IDX; /// divides by bit-size of type | |
| } | |
| void BitVecSHL(int[] bitvec, int n, int shift) { | |
| if( shift==0 || n<=0 ) { | |
| return; | |
| } | |
| int word_shift = shift >>> INT_BIT_LEN_IDX; | |
| int bit_shift = shift & (INT_BIT_LEN-1); | |
| int back_shift = INT_BIT_LEN - bit_shift; | |
| if( word_shift >= n ) { | |
| for( int i=0; i < n; i++ ) { | |
| bitvec[i] = 0; | |
| } | |
| return; | |
| } | |
| for( int i = n - 1; i >= 0; --i ) { | |
| int src = i - word_shift; | |
| bitvec[i] = (src >= 0)? bitvec[src] : 0; | |
| } | |
| if( bit_shift==0 ) { | |
| return; | |
| } | |
| int carry = 0; | |
| for( int i = word_shift; i < n; i++ ) { | |
| int cur = bitvec[i]; | |
| int next_carry = cur >>> back_shift; | |
| bitvec[i] = (cur << bit_shift) | carry; | |
| carry = next_carry; | |
| } | |
| int top = n - 1; | |
| bitvec[top] |= carry; | |
| } | |
| void BitVecSHR(int[] bitvec, int n, int shift) { | |
| if( shift==0 || n<=0 ) { | |
| return; | |
| } | |
| int word_shift = shift >>> INT_BIT_LEN_IDX; | |
| int bit_shift = shift & (INT_BIT_LEN-1); | |
| int back_shift = INT_BIT_LEN - bit_shift; | |
| if( word_shift >= n ) { | |
| for( int i=0; i < n; i++ ) { | |
| bitvec[i] = 0; | |
| } | |
| return; | |
| } | |
| for( int i=0; i < n; i++ ) { | |
| int src = i + word_shift; | |
| bitvec[i] = (src < n)? bitvec[src] : 0; | |
| } | |
| if( bit_shift==0 ) { | |
| return; | |
| } | |
| int carry = 0; | |
| for( int i = n-1; i >= 0; i-- ) { | |
| int cur = bitvec[i]; | |
| int next_carry = cur << back_shift; | |
| bitvec[i] = (cur >>> bit_shift) | carry; | |
| carry = next_carry; | |
| } | |
| } | |
| stock bool GenerateBitID(int[] gen_bits, int gen_bits_len, int &bits_idx) { | |
| /// make sure bit index is within range. | |
| if( bits_idx < 0 || bits_idx >= gen_bits_len ) { | |
| return false; | |
| } else if( bits_idx==(gen_bits_len - 1) && gen_bits[bits_idx]==0x80000000 ) { | |
| /// if LAST bitset bit is 1, we're out of component bits... | |
| return false; | |
| } else if( gen_bits[bits_idx]==0x80000000 ) { | |
| /// on last bit for the index, 0 and move 1 to the next index. | |
| gen_bits[bits_idx] = 0; | |
| bits_idx++; | |
| gen_bits[bits_idx] = 1; | |
| } else if( gen_bits[bits_idx]==0 ) { | |
| /// set up 1st bit so shifting can work. | |
| gen_bits[bits_idx] = 1; | |
| } else { | |
| gen_bits[bits_idx] <<= 1; | |
| } | |
| return true; | |
| } | |
| stock void BitVecSet(int[] bitvec, int bitidx) { | |
| bitvec[BitIndexToSlot(bitidx)] |= (1 << BitIndexToBitPos(bitidx)); | |
| } | |
| stock void BitVecClear(int[] bitvec, int bitidx) { | |
| bitvec[BitIndexToSlot(bitidx)] &= ~(1 << BitIndexToBitPos(bitidx)); | |
| } | |
| stock void BitVecToggle(int[] bitvec, int bitidx) { | |
| bitvec[BitIndexToSlot(bitidx)] ^= (1 << BitIndexToBitPos(bitidx)); | |
| } | |
| stock bool BitVecTest(const int[] bitvec, int bitidx) { | |
| return (bitvec[BitIndexToSlot(bitidx)] & (1 << BitIndexToBitPos(bitidx))) != 0; | |
| } | |
| stock void BitVecAND(const int[] bitvec1, const int[] bitvec2, int[] res, int n) { | |
| for( int i=0; i < n; i++ ) { | |
| res[i] = bitvec1[i] & bitvec2[i]; | |
| } | |
| } | |
| stock void BitVecOR(const int[] bitvec1, const int[] bitvec2, int[] res, int n) { | |
| for( int i=0; i < n; i++ ) { | |
| res[i] = bitvec1[i] | bitvec2[i]; | |
| } | |
| } | |
| stock void BitVecXOR(const int[] bitvec1, const int[] bitvec2, int[] res, int n) { | |
| for( int i=0; i < n; i++ ) { | |
| res[i] = bitvec1[i] ^ bitvec2[i]; | |
| } | |
| } | |
| stock int BitVecPopCount(const int[] bitvec, int n) { | |
| int count = 0; | |
| for( int i=0; i < n; i++ ) { | |
| count += PopCount(bitvec[i]); | |
| } | |
| return count; | |
| } | |
| stock void BitVecCopy(const int[] src, int[] dst, int n) { | |
| for( int i=0; i < n; i++ ) { | |
| dst[i] = src[i]; | |
| } | |
| } | |
| static stock void reverse_ints(int[] v, int lo, int hi) { | |
| while( lo < hi ) { | |
| int tmp = v[lo]; | |
| v[lo++] = v[hi]; | |
| v[hi--] = tmp; | |
| } | |
| } | |
| static stock void word_rotate_left(int[] v, int n, int k) { | |
| if( (k %= n)<=0 ) { | |
| return; | |
| } | |
| reverse_ints(v, 0, k-1); | |
| reverse_ints(v, k, n-1); | |
| reverse_ints(v, 0, n-1); | |
| } | |
| static stock void word_rotate_right(int[] v, int n, int k) { | |
| if( (k %= n)<=0 ) { | |
| return; | |
| } | |
| word_rotate_left(v, n, n - k); | |
| } | |
| stock void BitVecROTL(int[] bitvec, int n, int shift) { | |
| if( n<=0 ) { | |
| return; | |
| } | |
| int total_bits = INT_BIT_LEN * n; | |
| shift %= total_bits; | |
| if( shift <= 0 ) { | |
| return; | |
| } | |
| int word_shift = shift >>> INT_BIT_LEN_IDX; | |
| int bit_shift = shift & (INT_BIT_LEN - 1); | |
| word_rotate_right(bitvec, n, word_shift); | |
| if( bit_shift==0 ) { | |
| return; | |
| } | |
| int carry = 0; | |
| int back_shift = INT_BIT_LEN - bit_shift; | |
| for( int i=0; i < n; i++ ) { | |
| int cur = bitvec[i]; | |
| int next_carry = cur >>> back_shift; | |
| bitvec[i] = (cur << bit_shift) | carry; | |
| carry = next_carry; | |
| } | |
| bitvec[0] |= carry; | |
| } | |
| void BitVecROTR(int[] bitvec, int n, int shift) { | |
| if( n==0 ) { | |
| return; | |
| } | |
| int total_bits = INT_BIT_LEN * n; | |
| shift %= total_bits; | |
| if( shift==0 ) { | |
| return; | |
| } | |
| int word_shift = shift >>> INT_BIT_LEN_IDX; | |
| int bit_shift = shift & (INT_BIT_LEN - 1); | |
| word_rotate_left(bitvec, n, word_shift); | |
| if( bit_shift==0 ) { | |
| return; | |
| } | |
| int carry = 0; | |
| int back_shift = INT_BIT_LEN - bit_shift; | |
| for( int i = n-1; i >= 0; i-- ) { | |
| int cur = bitvec[i]; | |
| int next_carry = cur << back_shift; | |
| bitvec[i] = (cur >>> bit_shift) | carry; | |
| carry = next_carry; | |
| } | |
| bitvec[n-1] |= carry; | |
| } | |
| /// int[][] player_bits = new int[MaxClients][NUM_BITS]; | |
| stock void BitSetCopy(int n, const int[][] bits2D, int[] buf, int buflen) { | |
| for( int i; i < buflen; i++ ) { | |
| buf[i] = bits2D[n][i]; | |
| } | |
| } | |
| stock void BitSetSetByBits(int n, int[][] bits2D, const int[] query_bits, int bits_len) { | |
| for( int i; i < bits_len; i++ ) { | |
| bits2D[n][i] |= query_bits[i]; | |
| } | |
| } | |
| stock void BitSetSetByBitIdx(int n, int[][] bits2D, int bitidx) { | |
| BitVecSet(bits2D[n], bitidx); | |
| } | |
| stock void BitSetClearByBits(int n, int[][] bits2D, const int[] query_bits, int bits_len) { | |
| for( int i; i < bits_len; i++ ) { | |
| bits2D[n][i] &= ~query_bits[i]; | |
| } | |
| } | |
| stock void BitSetClearByBitIdx(int n, int[][] bits2D, int bitidx) { | |
| BitVec_Clear(bits2D[n], bitidx); | |
| } | |
| stock bool BitSetHas(int n, const int[][] bits2D, const int[] query_bits, int bits_len) { | |
| bool result = true; | |
| for( int i; i < bits_len; i++ ) { | |
| if( query_bits[i]==0 ) { | |
| continue; | |
| } | |
| result = result && (bits2D[n][i] & query_bits[i]) != 0; | |
| } | |
| return result; | |
| } | |
| /// int[] player_buf = new int[MaxClients]; | |
| stock int QueryPlayers(const int[][] bits2D, const int[] query_bits, int bits_len, int[] player_buf) { | |
| int k; | |
| for( int i=MaxClients; i > 0; i-- ) { | |
| if( !(0 < 1 <= MaxClients && IsClientInGame(i)) ) { | |
| continue; | |
| } else if( BitSet_Has(i, bits2D, query_bits, bits_len) ) { | |
| player_buf[k++] = GetClientUserId(i); | |
| } | |
| } | |
| return k; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * ecs_helper.inc | |
| * | |
| * Copyright [2022] Nergal the Ashurian | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| * this software and associated documentation files (the "Software"), | |
| * to deal in the Software without restriction, | |
| * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, | |
| * subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
| * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. | |
| * | |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| * | |
| */ | |
| #if defined _ecs_helper_included | |
| #endinput | |
| #endif | |
| #define _ecs_helper_included | |
| #include <sourcemod> | |
| /** | |
| * Entity Component System for SourcePawn. | |
| * | |
| * Entities & Components | |
| * * An entity is a unique identifier [userids and entity references] | |
| * * A component can optionally be associated with a plain old datatype [enum struct, methodmap, or array data] | |
| * * A component identifier is an entity [handled via int or handle types] | |
| * * An entity can have 0 ... N components | |
| * * A component can be annotated with a role | |
| * * An <entity, component> tuple can have 0 ... N components | |
| * | |
| * An action called a 'query' filters entities by a matching set of components. | |
| * | |
| * | |
| * Systems | |
| * * A system is logic matched with entities based on their components | |
| * * A system is invoked as result of an event | |
| * * A component mutation is an event | |
| * * Computing a simulation frame is an event | |
| * * A frame is divided into N phases | |
| * * Each system is assigned to a phase | |
| * | |
| * In a nutshell, Systems are an entity-component query & a callback. | |
| */ | |
| /// with 4 bit-counts, max 128 components per entity. | |
| /// 4 * 32 == 128 bits. | |
| enum { | |
| COMPONENT_BIT_LEN = 1024, | |
| INT_BIT_LEN = 32, | |
| INT_BIT_LEN_IDX = 5, | |
| }; | |
| enum { | |
| COMPONENT_LEN = COMPONENT_BIT_LEN / INT_BIT_LEN, | |
| }; | |
| stock int BitOfBitIdx(int bitidx) { | |
| return bitidx & (INT32_BIT_LEN-1); /// modulos by bit-size of type | |
| } | |
| stock int SlotOfBitIdx(int bitidx) { | |
| return bitidx >>> INT32_BIT_LEN_IDX; /// divides by bit-size of type | |
| } | |
| /// returns the index of where the bit is used. | |
| stock int BitIndexToSlotAndBit(int bitidx, int &bit) { | |
| bit = BitOfBitIdx(bitidx); | |
| return SlotOfBitIdx(bitidx); | |
| } | |
| stock int SlotAndBitToBitIndex(int slot, int bit) { | |
| return (slot << (INT_BIT_LEN_IDX)) + bit; | |
| } | |
| stock bool GenerateBitID(int[] gen_bits, int gen_bits_len, int &arr_idx, int &bit_idx=0) { | |
| /// make sure bit index is within range. | |
| if( arr_idx < 0 || arr_idx >= gen_bits_len ) { | |
| return false; | |
| } else if( arr_idx==(gen_bits_len - 1) && gen_bits[arr_idx]==0x80000000 ) { | |
| /// if LAST bitset bit is 1, we're out of component bits... | |
| bit_idx = COMPONENT_BIT_LEN; | |
| return false; | |
| } else if( gen_bits[arr_idx]==0x80000000 ) { | |
| /// on last bit for the index, 0 and move 1 to the next index. | |
| gen_bits[arr_idx] = 0; | |
| arr_idx++; | |
| gen_bits[arr_idx] = 1; | |
| bit_idx++; | |
| } else if( gen_bits[arr_idx]==0 ) { | |
| /// set up 1st bit so shifting can work. | |
| gen_bits[arr_idx] = 1; | |
| bit_idx = 0; | |
| } else { | |
| gen_bits[arr_idx] <<= 1; | |
| bit_idx++; | |
| } | |
| return true; | |
| } | |
| stock void BitVec_Set(int[] bitvec, int bitidx) { | |
| int bit; | |
| int slot = BitIndexToSlotAndBit(bitidx, bit); | |
| bitvec[slot] |= (1 << bit); | |
| } | |
| stock void BitVec_Clear(int[] bitvec, int bitidx) { | |
| int bit; | |
| int slot = BitIndexToSlotAndBit(bitidx, bit); | |
| bitvec[slot] &= ~(1 << bit); | |
| } | |
| stock void BitVec_Toggle(int[] bitvec, int bitidx) { | |
| int bit; | |
| int slot = BitIndexToSlotAndBit(bitidx, bit); | |
| bitvec[slot] ^= (1 << bit); | |
| } | |
| stock bool BitVec_Has(int[] bitvec, int bitidx) { | |
| int bit; | |
| int slot = BitIndexToSlotAndBit(bitidx, bit); | |
| return (bitvec[slot] & (1 << bit)) > 0; | |
| } | |
| stock void BitSet_Copy(int n, int[][] bits2D, int[] buf, int buflen) { | |
| for( int i; i < buflen; i++ ) { | |
| buf[i] = bits2D[n][i]; | |
| } | |
| } | |
| stock void BitSet_SetByBits(int n, int[][] bits2D, int[] query_bits, int bits_len) { | |
| for( int i; i < bits_len; i++ ) { | |
| bits2D[n][i] |= query_bits[i]; | |
| } | |
| } | |
| stock void BitSet_SetByBitIdx(int n, int[][] bits2D, int bitidx) { | |
| BitVec_Set(bits2D[n], bitidx); | |
| } | |
| stock void BitSet_ClearByBits(int n, int[][] bits2D, int[] query_bits, int bits_len) { | |
| for( int i; i < bits_len; i++ ) { | |
| bits2D[n][i] &= ~query_bits[i]; | |
| } | |
| } | |
| stock void BitSet_ClearByBitIdx(int n, int[][] bits2D, int bitidx) { | |
| BitVec_Clear(bits2D[n], bitidx); | |
| } | |
| stock bool BitSet_Has(int n, int[][] bits2D, int[] query_bits, int bits_len) { | |
| bool result = true; | |
| for( int i; i < bits_len; i++ ) { | |
| if( query_bits[i]==0 ) { | |
| continue; | |
| } | |
| result = result && (bits2D[n][i] & query_bits[i]) > 0; | |
| } | |
| return result; | |
| } | |
| stock int QueryPlayers(int[][] bits2D, int[] query_bits, int bits_len, int[/** MaxClients */] player_buf) { | |
| int k; | |
| for( int i=MaxClients; i > 0; i-- ) { | |
| if( !(0 < i <= MaxClients) || !IsClientInGame(i) ) { | |
| continue; | |
| } else if( BitSet_Has(i, bits2D, query_bits, bits_len) ) { | |
| player_buf[k++] = GetClientUserId(i); | |
| } | |
| } | |
| return k; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment