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