001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.util.AllocationException;
011import edu.wpi.first.wpilibj.util.CheckedAllocationException;
012
013/**
014 * Track resources in the program. The Resource class is a convenient way of keeping track of
015 * allocated arbitrary resources in the program. Resources are just indices that have an lower and
016 * upper bound that are tracked by this class. In the library they are used for tracking allocation
017 * of hardware channels but this is purely arbitrary. The resource class does not do any actual
018 * allocation, but simply tracks if a given index is currently in use.
019 *
020 * <p><b>WARNING:</b> this should only be statically allocated. When the program loads into memory
021 * all the static constructors are called. At that time a linked list of all the "Resources" is
022 * created. Then when the program actually starts - in the Robot constructor, all resources are
023 * initialized. This ensures that the program is restartable in memory without having to
024 * unload/reload.
025 */
026public final class Resource {
027  private static Resource resourceList = null;
028  private final boolean[] m_numAllocated;
029  private final int m_size;
030  private final Resource m_nextResource;
031
032  /**
033   * Clears all allocated resources.
034   */
035  public static void restartProgram() {
036    for (Resource r = Resource.resourceList; r != null; r = r.m_nextResource) {
037      for (int i = 0; i < r.m_size; i++) {
038        r.m_numAllocated[i] = false;
039      }
040    }
041  }
042
043  /**
044   * Allocate storage for a new instance of Resource. Allocate a bool array of values that will get
045   * initialized to indicate that no resources have been allocated yet. The indices of the
046   * resources are 0..size-1.
047   *
048   * @param size The number of blocks to allocate
049   */
050  public Resource(final int size) {
051    m_size = size;
052    m_numAllocated = new boolean[size];
053    for (int i = 0; i < size; i++) {
054      m_numAllocated[i] = false;
055    }
056    m_nextResource = Resource.resourceList;
057    Resource.resourceList = this;
058  }
059
060  /**
061   * Allocate a resource. When a resource is requested, mark it allocated. In this case, a free
062   * resource value within the range is located and returned after it is marked allocated.
063   *
064   * @return The index of the allocated block.
065   * @throws CheckedAllocationException If there are no resources available to be allocated.
066   */
067  public int allocate() throws CheckedAllocationException {
068    for (int i = 0; i < m_size; i++) {
069      if (!m_numAllocated[i]) {
070        m_numAllocated[i] = true;
071        return i;
072      }
073    }
074    throw new CheckedAllocationException("No available resources");
075  }
076
077  /**
078   * Allocate a specific resource value. The user requests a specific resource value, i.e. channel
079   * number and it is verified unallocated, then returned.
080   *
081   * @param index The resource to allocate
082   * @return The index of the allocated block
083   * @throws CheckedAllocationException If there are no resources available to be allocated.
084   */
085  public int allocate(final int index) throws CheckedAllocationException {
086    if (index >= m_size || index < 0) {
087      throw new CheckedAllocationException("Index " + index + " out of range");
088    }
089    if (m_numAllocated[index]) {
090      throw new CheckedAllocationException("Resource at index " + index + " already allocated");
091    }
092    m_numAllocated[index] = true;
093    return index;
094  }
095
096  /**
097   * Free an allocated resource. After a resource is no longer needed, for example a destructor is
098   * called for a channel assignment class, Free will release the resource value so it can be reused
099   * somewhere else in the program.
100   *
101   * @param index The index of the resource to free.
102   */
103  public void free(final int index) {
104    if (!m_numAllocated[index]) {
105      throw new AllocationException("No resource available to be freed");
106    }
107    m_numAllocated[index] = false;
108  }
109
110}