001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. 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.
015 * The Resource class is a convenient way of keeping track of allocated arbitrary resources
016 * in the program. Resources are just indicies that have an lower and upper bound that are
017 * tracked by this class. In the library they are used for tracking allocation of hardware channels
018 * but this is purely arbitrary. The resource class does not do any actual allocation, but
019 * simply tracks if a given index is currently in use.
020 *
021 * WARNING: this should only be statically allocated. When the program loads into memory all the
022 * static constructors are called. At that time a linked list of all the "Resources" is created.
023 * Then when the program actually starts - in the Robot constructor, all resources are initialized.
024 * This ensures that the program is restartable in memory without having to unload/reload.
025 */
026public class Resource {
027
028    private static Resource m_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.m_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.
046     * Allocate a bool array of values that will get initialized to indicate that no resources
047     * have been allocated yet. The indicies of the 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[m_size];
054        for (int i = 0; i < m_size; i++) {
055            m_numAllocated[i] = false;
056        }
057        m_nextResource = Resource.m_resourceList;
058        Resource.m_resourceList = this;
059    }
060
061    /**
062     * Allocate a resource.
063     * When a resource is requested, mark it allocated. In this case, a free resource value
064     * within the range is located and returned after it is marked allocated.
065     *
066     * @return The index of the allocated block.
067     * @throws CheckedAllocationException If there are no resources available to be allocated.
068     */
069    public int allocate() throws CheckedAllocationException {
070        for (int i = 0; i < m_size; i++) {
071            if (m_numAllocated[i] == false) {
072                m_numAllocated[i] = true;
073                return i;
074            }
075        }
076        throw new CheckedAllocationException("No available resources");
077    }
078
079    /**
080     * Allocate a specific resource value.
081     * The user requests a specific resource value, i.e. channel number and it is verified
082     * unallocated, then returned.
083     *
084     * @param index The resource to allocate
085     * @return The index of the allocated block
086     * @throws CheckedAllocationException If there are no resources available to be allocated.
087     */
088    public int allocate(final int index) throws CheckedAllocationException {
089        if (index >= m_size || index < 0) {
090            throw new CheckedAllocationException("Index " + index + " out of range");
091        }
092        if (m_numAllocated[index] == true) {
093            throw new CheckedAllocationException("Resource at index " + index + " already allocated");
094        }
095        m_numAllocated[index] = true;
096        return index;
097    }
098
099    /**
100     * Free an allocated resource.
101     * After a resource is no longer needed, for example a destructor is called for a channel assignment
102     * class, Free will release the resource value so it can be reused somewhere else in the program.
103     *
104     * @param index The index of the resource to free.
105     */
106    public void free(final int index) {
107        if (m_numAllocated[index] == false)
108            throw new AllocationException("No resource available to be freed");
109        m_numAllocated[index] = false;
110    }
111    
112}