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