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