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 */ 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, this method will release the resource value, so it can 094 * be reused 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}