001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. 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 indicies 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
028  private static Resource resourceList = null;
029  private final boolean[] m_numAllocated;
030  private final int m_size;
031  private final Resource m_nextResource;
032
033  /**
034   * Clears all allocated resources.
035   */
036  public static void restartProgram() {
037    for (Resource r = Resource.resourceList; r != null; r = r.m_nextResource) {
038      for (int i = 0; i < r.m_size; i++) {
039        r.m_numAllocated[i] = false;
040      }
041    }
042  }
043
044  /**
045   * Allocate storage for a new instance of Resource. Allocate a bool array of values that will get
046   * initialized to indicate that no resources have been allocated yet. The indicies of the
047   * resources are 0..size-1.
048   *
049   * @param size The number of blocks to allocate
050   */
051  public Resource(final int size) {
052    m_size = size;
053    m_numAllocated = new boolean[size];
054    for (int i = 0; i < size; i++) {
055      m_numAllocated[i] = false;
056    }
057    m_nextResource = Resource.resourceList;
058    Resource.resourceList = this;
059  }
060
061  /**
062   * Allocate a resource. When a resource is requested, mark it allocated. In this case, a free
063   * resource value within the range is located and returned after it is marked allocated.
064   *
065   * @return The index of the allocated block.
066   * @throws CheckedAllocationException If there are no resources available to be allocated.
067   */
068  public int allocate() throws CheckedAllocationException {
069    for (int i = 0; i < m_size; i++) {
070      if (m_numAllocated[i] == false) {
071        m_numAllocated[i] = true;
072        return i;
073      }
074    }
075    throw new CheckedAllocationException("No available resources");
076  }
077
078  /**
079   * Allocate a specific resource value. The user requests a specific resource value, i.e. channel
080   * number and it is verified unallocated, then returned.
081   *
082   * @param index The resource to allocate
083   * @return The index of the allocated block
084   * @throws CheckedAllocationException If there are no resources available to be allocated.
085   */
086  public int allocate(final int index) throws CheckedAllocationException {
087    if (index >= m_size || index < 0) {
088      throw new CheckedAllocationException("Index " + index + " out of range");
089    }
090    if (m_numAllocated[index] == true) {
091      throw new CheckedAllocationException("Resource at index " + index + " already allocated");
092    }
093    m_numAllocated[index] = true;
094    return index;
095  }
096
097  /**
098   * Free an allocated resource. After a resource is no longer needed, for example a destructor is
099   * called for a channel assignment class, Free will release the resource value so it can be reused
100   * somewhere else in the program.
101   *
102   * @param index The index of the resource to free.
103   */
104  public void free(final int index) {
105    if (m_numAllocated[index] == false) {
106      throw new AllocationException("No resource available to be freed");
107    }
108    m_numAllocated[index] = false;
109  }
110
111}