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    
008    package edu.wpi.first.wpilibj;
009    
010    import edu.wpi.first.wpilibj.util.AllocationException;
011    import 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     */
026    public 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) {
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    }