public static void IsValidValue(int value, string argumentName) { ContractExtensions.IsArgumentInRange(value > 0, argumentName, "Value has to be > 0"); ContractExtensions.IsArgumentInRange(value <= 9, argumentName, "Value has to be <= 9"); Contract.EndContractBlock(); }
public static void IsValidIndex(int zeroBasedIndex, string argumentName) { ContractExtensions.IsArgumentInRange(zeroBasedIndex >= 0, argumentName, "Index has to be >= 0"); ContractExtensions.IsArgumentInRange(zeroBasedIndex < 9, argumentName, "Index has to be < 9"); Contract.EndContractBlock(); }
/// <summary> /// Initializes a new instance of the <see cref="BoardStreamRepository"/> class. /// </summary> /// <param name="streamManager">Underlying stream manager.</param> public BoardStreamRepository(IStreamManager streamManager) { ContractExtensions.IsNotNull(streamManager, "streamManager"); Contract.Ensures(this.streamManager != null); Contract.EndContractBlock(); this.streamManager = streamManager; }
/// <summary> /// Initializes a new instance of the <see cref="CloudBlobStreamManager"/> class. /// </summary> /// <param name="container">The container in which the boards should be stored.</param> public CloudBlobStreamManager(CloudBlobContainer container) { ContractExtensions.IsNotNull(container, "container"); Contract.Ensures(this.container != null); Contract.EndContractBlock(); this.container = container; }
public static Board FromBytes(byte[] source) { // The following lines represent the contracts that are checked even in release builds. // Commonly used contracts were extracted into the ContractExtensions helper class. // Note the use of the ContractArgumentValidator attribute in the helper methods. // Note that you can set the 'Emit contracts into XML doc file' project option for // code contracts. If you do so, Sandcastle will include the contract in the generated // documentation. ContractExtensions.IsNotNull(source, "source"); ContractExtensions.IsArgumentInRange(source.Length == 9 * 9, "source", "Source does not have correct size (9 * 9 = 81 elements)"); if (Contract.ForAll(source, cellValue => cellValue < 0 || cellValue > 9)) { throw new ArgumentException("Source contains invalid values"); } Contract.EndContractBlock(); var result = new Board(); try { for (byte rowIndex = 0, index = 0; rowIndex < 9; rowIndex++) { for (byte columnIndex = 0; columnIndex < 9; columnIndex++, index++) { // Store content of source[index] in a variable because it is accessed multiple times. var cellValue = source[index]; // Ignore zero if (cellValue != 0) { // Note that it is not necessary to protect board bytes because result // has just been created and nobody else has a reference on it. if (!Board.TrySetCellInternal(result.content, rowIndex, columnIndex, cellValue)) { throw new BoardException(string.Format( CultureInfo.InvariantCulture, "Specified source contains invalid value {0} in cell (row {1}, column {2})", cellValue, rowIndex, columnIndex)); } } } } } catch { // Dispose created board in case of an exception result.Dispose(); throw; } return(result); }
public static Task <Board> LoadFromFileAsync(string boardName, string boardsDirectory = null) { ContractExtensions.IsNotNull(boardName, "boardName"); Contract.EndContractBlock(); var streamManager = boardsDirectory == null ? new FileStreamManager() : new FileStreamManager(boardsDirectory); var repository = new BoardStreamRepository(streamManager); return(repository.LoadAsync(boardName)); }
/// <summary> /// Gets the <see cref="BoardRow"/> with the specified zero based row index. /// </summary> /// <value> /// The <see cref="BoardRow"/> at index <paramref name="zeroBasedRowIndex"/>. /// </value> /// <param name="zeroBasedRowIndex">Index of the row.</param> public BoardRow this[int zeroBasedRowIndex] { get { ContractExtensions.IsNotDisposed(this, this.IsDisposed); ContractExtensions.IsValidIndex(zeroBasedRowIndex, "zeroBasedRowIndex"); Contract.EndContractBlock(); return(this.rows[zeroBasedRowIndex]); } }
/// <summary> /// Gets or sets the value of the cell at the specified column index. /// </summary> /// <value> /// The value of the cell. /// </value> /// <param name="zeroBasedColumnIndex">Index of the column.</param> public byte this[int zeroBasedColumnIndex] { get { ContractExtensions.IsValidIndex(zeroBasedColumnIndex, "zeroBasedColumnIndex"); return(this.getter(zeroBasedColumnIndex)); } set { ContractExtensions.IsValidIndex(zeroBasedColumnIndex, "zeroBasedColumnIndex"); this.setter(zeroBasedColumnIndex, value); } }
/// <summary> /// Loads board from Azure Blob Storage asynchronously. /// </summary> /// <param name="accountName">Name of the Windows Azure Storage account.</param> /// <param name="accountKey">Key for the Windows Azure Storaeg account.</param> /// <param name="containerName">Container in which boards are stored.</param> /// <param name="boardName">Name of the board.</param> /// <returns> /// A task that represents the asynchronous operation. The value of the /// TResult parameter contains the loaded board. /// </returns> public static Task <Board> LoadFromBlobStorageAsync(string accountName, string accountKey, string containerName, string boardName) { ContractExtensions.IsNotNull(accountName, "accountName"); ContractExtensions.IsNotNull(accountKey, "accountKey"); ContractExtensions.IsNotNull(containerName, "containerName"); Contract.EndContractBlock(); var credentials = new StorageCredentials(accountName, accountKey); var account = new CloudStorageAccount(credentials, true); var client = account.CreateCloudBlobClient(); var container = client.GetContainerReference(containerName); var repository = new BoardStreamRepository(new CloudBlobStreamManager(container)); return(repository.LoadAsync(boardName)); }
/// <summary> /// Resets a cell's value to unset. /// </summary> /// <param name="zeroBasedRowIndex">Index of the row.</param> /// <param name="zeroBasedColumnIndex">Index of the column.</param> public void ResetCell(int zeroBasedRowIndex, int zeroBasedColumnIndex) { ContractExtensions.IsNotDisposed(this, this.IsDisposed); ContractExtensions.IsValidIndex(zeroBasedRowIndex, "zeroBasedRowIndex"); ContractExtensions.IsValidIndex(zeroBasedColumnIndex, "zeroBasedColumnIndex"); Contract.EndContractBlock(); this.contentLock.EnterWriteLock(); try { this.content[Board.CalculateIndexFromRowAndColumn(zeroBasedRowIndex, zeroBasedColumnIndex)] = 0; } finally { this.contentLock.ExitWriteLock(); } }
/// <summary> /// Saves the board using the specified name /// </summary> /// <param name="boardName">Name of the board.</param> /// <param name="board">The board to save.</param> /// <returns>A task that represents the asynchronous operation.</returns> public async Task SaveAsync(string boardName, Board board) { ContractExtensions.IsNotNull(boardName, "boardName"); ContractExtensions.IsNotNull(board, "board"); Contract.Ensures(Contract.Result <Task>() != null); Contract.EndContractBlock(); // Open underlying stream for writing using (var stream = await this.streamManager.OpenStreamAsync(boardName, AccessMode.Write)) { // Get byte array from board and save it. var boardData = (byte[])board; // Note the use of ConfigureAwait(false) here. await stream.WriteAsync(boardData, 0, boardData.Length) .ConfigureAwait(false); } }
/// <summary> /// Gets the value of a cell. /// </summary> /// <param name="zeroBasedRowIndex">Index of the row.</param> /// <param name="zeroBasedColumnIndex">Index of the column.</param> /// <returns>Value of the cell at the specified row and column index.</returns> /// <remarks> /// Zero is returned for an unset cell. /// </remarks> public byte GetCell(int zeroBasedRowIndex, int zeroBasedColumnIndex) { ContractExtensions.IsNotDisposed(this, this.IsDisposed); ContractExtensions.IsValidIndex(zeroBasedRowIndex, "zeroBasedRowIndex"); ContractExtensions.IsValidIndex(zeroBasedColumnIndex, "zeroBasedColumnIndex"); Contract.EndContractBlock(); // Note that we use a read lock this time. This makes sure that many threads // can read the board's content at the same time. this.contentLock.EnterReadLock(); try { return(this.content[Board.CalculateIndexFromRowAndColumn(zeroBasedRowIndex, zeroBasedColumnIndex)]); } finally { this.contentLock.ExitReadLock(); } }
/// <summary> /// Converts <see cref="Board"/> instance to bytes. /// </summary> /// <param name="source">Source board.</param> /// <returns>Board data as a byte array.</returns> public static byte[] ToBytes(Board source) { ContractExtensions.IsNotNull(source, "source"); ContractExtensions.IsNotDisposed(source, source.IsDisposed); Contract.EndContractBlock(); var result = new byte[9 * 9]; source.contentLock.EnterReadLock(); try { source.content.CopyTo(result, 0); return(result); } finally { source.contentLock.ExitReadLock(); } }
public byte[] GetCopyOfRow(int zeroBasedRowIndex) { ContractExtensions.IsNotDisposed(this, this.IsDisposed); ContractExtensions.IsValidIndex(zeroBasedRowIndex, "zeroBasedRowIndex"); Contract.EndContractBlock(); var result = new byte[9]; this.contentLock.EnterReadLock(); try { Array.Copy(this.content, zeroBasedRowIndex * 9, result, 0, 9); } finally { this.contentLock.ExitReadLock(); } return(result); }
/// <summary> /// Tries the set the value of a cell. /// </summary> /// <param name="zeroBasedRowIndex">Index of the row.</param> /// <param name="zeroBasedColumnIndex">Index of the column.</param> /// <param name="value">The new value.</param> /// <returns><c>True</c> if the value could be set successfully, otherwise <c>false</c>.</returns> /// <remarks> /// <para> /// Note that <paramref name="value"/> must not be zero. If you want to unset a cell, /// use <see cref="ResetCell"/> instead. /// </para> /// <para> /// Note the TryXXX naming pattern. <see cref="TrySetCell"/> does the same as <see cref="SetCell"/> /// except that it does not throw an exception if the value could not be set. /// </para> /// </remarks> public bool TrySetCell(int zeroBasedRowIndex, int zeroBasedColumnIndex, byte value) { ContractExtensions.IsNotDisposed(this, this.IsDisposed); ContractExtensions.IsValidIndex(zeroBasedRowIndex, "zeroBasedRowIndex"); ContractExtensions.IsValidIndex(zeroBasedColumnIndex, "zeroBasedColumnIndex"); ContractExtensions.IsValidValue(value, "value"); Contract.EndContractBlock(); // Note that we use a write lock this time. This makes sure that only one thread // can write to the board bytes at the same time. this.contentLock.EnterWriteLock(); try { // Call internal implementation. return(Board.TrySetCellInternal(this.content, zeroBasedRowIndex, zeroBasedColumnIndex, value)); } finally { this.contentLock.ExitWriteLock(); } }
/// <summary> /// Loads the board using the specified name /// </summary> /// <param name="boardName">Name of the board to load.</param> /// <returns> /// A task that represents the asynchronous operation. The value of the /// TResult parameter contains the loaded board. /// </returns> public async Task <Board> LoadAsync(string boardName) { ContractExtensions.IsNotNull(boardName, "boardName"); Contract.Ensures(Contract.Result <Task <Board> >() != null); Contract.Ensures(Contract.Result <Task <Board> >().Result != null); Contract.EndContractBlock(); // Open underlying stream for reading using (var stream = await this.streamManager.OpenStreamAsync(boardName, AccessMode.Read)) { // Load board content var boardData = new byte[9 * 9]; var resultLength = await stream.ReadAsync(boardData, 0, boardData.Length).ConfigureAwait(false); if (resultLength != 9 * 9) { // Board stream has to be at least 9 * 9 bytes long. throw new BoardException("Incorrect file format. Board file too small."); } // Convert board data. This will throw an exception if the board data is invalid. return((Board)boardData); } }