/// <summary> /// Sets the bits in the region starting at location and having /// given width and height /// </summary> /// <param name="location">Top Left of the the Region</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> internal void SetRegion(MatrixCell location, int width, int height) { long targetRow = location.Row; long targetCol = location.Col; int targetWidth = width; int targetHeight = height; // Interchange Row & Column and width & height if the BitOrientation is Vertical if (BitOrientation == Orientation.Vertical) { targetRow = location.Col; targetCol = location.Row; targetWidth = height; targetHeight = width; } // Optimization: If the region is only 1 bit wide and high if ((targetWidth == 1) && (targetHeight == 1)) { this[targetRow, targetCol] = true; return; } for (var row = 0; row < targetHeight; row++) { for (var col = 0; col < targetWidth; col++) { this[targetRow + row, targetCol + col] = true; } } }
/// <summary> /// Sets the bits in the region starting at location and having /// given width and height /// </summary> /// <param name="location">Top Left of the the Region</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> internal void SetRegion(MatrixCell location, int width, int height) { if (BitOrientation == Orientation.Horizontal) { // Optimization: If the region is only 1 bit wide and high if ((width == 1) && (height == 1)) { this[location.Row, location.Col] = true; return; } for (var row = 0; row < height; row++) { for (var col = 0; col < width; col++) { this[location.Row + row, location.Col + col] = true; } } } // Interchange Row & Column and width & height if the BitOrientation is Vertical else { // Optimization: If the region is only 1 bit wide and high if ((width == 1) && (height == 1)) { this[location.Col, location.Row] = true; return; } for (var row = 0; row < width; row++) { for (var col = 0; col < height; col++) { this[location.Col + row, location.Row + col] = true; } } } }
/// <summary> /// Finds the next empty region of given width and height starting /// from the startIndex row /// </summary> /// <param name="startIndex">The row to start the search from</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> /// <returns></returns> internal MatrixCell FindRegion(long startIndex, int width, int height) { // Swap width and height if the BitOrientation is Vertical if ((BitOrientation == Orientation.Vertical) && (width != height)) { var temp = width; width = height; height = temp; } var invalidCell = new MatrixCell(-1, -1); if (startIndex < 0 || startIndex >= _rowsInternal) { throw new ArgumentOutOfRangeException(nameof(startIndex)); } if (startIndex + (height - 1) >= _rowsInternal) { throw new ArgumentOutOfRangeException(nameof(width), $"Cannot fit item having height of {height} rows in {_rowsInternal - startIndex} rows!"); } if ((width < 1) || (width > 60)) { throw new ArgumentOutOfRangeException(nameof(width), $"Length of the item must be in the range 1 - {MaxBitsPerItem}!"); } if (width > _columnsInternal) { throw new ArgumentOutOfRangeException(nameof(width), $"Length cannot be greater than number of columns in the BitMatrix!"); } // Optimization: If both width and height are 1 then use a faster // loop to find the next empty bit if ((width == 1) && (height == 1)) { for (var row = startIndex; row < _rowsInternal; row++) { for (var col = 0; col < _columnsInternal; col++) { if (!this[row, col]) { // Swap the row and col values if the BitOrientation is Vertical return((BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, col) : new MatrixCell(col, row)); } } } // If the code has reached here it means that it did not find any unset // bit in the entire _data. Simply return from here. return(invalidCell); } var mask = (((UInt64)1) << width) - 1; for (var row = startIndex; row < _rowsInternal; row++) { // Quickcheck: If the row is empty then no need to check individual bits in the row if (!RowHasData(row)) { // Current column has no bits set. Check the bits in the next (height - 1) // rows starting at the same column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical return((BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row)); } } // Row is not empty and has some set bits. Check if there are // 'width' continuous unset bits in the column. // 1. Check the first 'width' bits var rowData = (UInt64)0; var col = 0; for (; col < width; col++) { rowData <<= 1; rowData |= this[row, col] ? (UInt64)1 : (UInt64)0; } if ((rowData & mask) == 0) { // Current column has 'width' unset bits starting from 0 position. // Check the bits in the next (height - 1) rows starting at the same // column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical return((BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row)); } } // Shift the rowData by 1 bit and clear the (width + 1)th most significant bit. // This way a set of 'width' continuous bits is matched against the mask // to check if all the bits are zero. var colBegin = 0; while (col < _columnsInternal) { rowData <<= 1; rowData &= mask; rowData |= this[row, col++] ? (UInt64)1 : (UInt64)0; colBegin++; if ((rowData & mask) != 0) { continue; } // Current column has 'width' unset bits starting from colBegin position. // Check the bits in the next (height - 1) rows starting at the same // column position (colBegin) to check if they are unset if (AnyBitsSetInRegion(row, colBegin, width, height)) { continue; } // Swap the row and col values if the BitOrientation is Vertical return((BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, colBegin) : new MatrixCell(colBegin, row)); } } return(invalidCell); }
/// <summary> /// Tries to find an empty region of given width and height starting /// from the startIndex row. /// </summary> /// <param name="startIndex">The row to start the search from</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> /// <param name="cell">The cell location</param> /// <returns>true if successful otherwise false</returns> internal bool TryFindRegion(long startIndex, int width, int height, out MatrixCell cell) { cell = MatrixCell.InvalidCell(); // Swap width and height if the BitOrientation is Vertical if ((BitOrientation == Orientation.Vertical) && (width != height)) { var temp = width; width = height; height = temp; } if ((startIndex < 0 || startIndex >= _rowsInternal) || (startIndex + (height - 1) >= _rowsInternal) || ((width < 1) || (width > MaxBitsPerItem)) || (width > _columnsInternal)) { return(false); } // Optimization: If both width and height are 1 then use a faster // loop to find the next empty cell if ((width == 1) && (height == 1)) { for (var row = startIndex; row < _rowsInternal; row++) { for (var col = 0; col < _columnsInternal; col++) { // Is the cell unset? if (this[row, col]) { continue; } // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, col) : new MatrixCell(col, row); return(true); } } // If the code has reached here it means that it did not find any unset // bit in the entire matrix. Return false from here. return(false); } var mask = (((UInt64)1) << width) - 1; for (var row = startIndex; row < (_rowsInternal - height + 1); row++) { // Quickcheck: If the row is empty then no need to check individual bits in the row if (!RowHasData(row)) { // Current column has no bits set. Check the bits in the next (height - 1) // rows starting at the same column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); return(true); } } // Row is not empty and has some set bits. Check if there are // 'width' continuous unset bits in the column. // 1. Check the first 'width' bits var rowData = 0UL; var col = 0; for (; col < width; col++) { rowData <<= 1; rowData |= this[row, col] ? 1UL : 0UL; } if ((rowData & mask) == 0) { // Current column has 'width' unset bits starting from 0 position. // Check the bits in the next (height - 1) rows starting at the same // column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); return(true); } } // Shift the rowData by 1 bit and clear the (width + 1)th most significant bit. // This way a set of 'width' continuous bits is matched against the mask // to check if all the bits are zero. var colBegin = 0; while (col < _columnsInternal) { rowData <<= 1; rowData &= mask; rowData |= this[row, col++] ? 1UL : 0UL; colBegin++; if ((rowData & mask) != 0) { continue; } // Current column has 'width' unset bits starting from colBegin position. // Check the bits in the next (height - 1) rows starting at the same // column position (colBegin) to check if they are unset if (AnyBitsSetInRegion(row, colBegin, width, height)) { continue; } // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, colBegin) : new MatrixCell(colBegin, row); return(true); } } return(false); }