1 /*
2 * Entreri, an entity-component framework in Java
3 *
4 * Copyright (c) 2013, Michael Ludwig
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 package com.lhkbob.entreri.property;
28
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.Arrays;
32
33 /**
34 * IntProperty is an implementation of Property that stores a single int value.
35 *
36 * @author Michael Ludwig
37 */
38 @Factory(IntProperty.Factory.class)
39 public final class IntProperty implements Property {
40 private int[] data;
41
42 /**
43 * Create an IntProperty.
44 */
45 public IntProperty() {
46 data = new int[1];
47 }
48
49 /**
50 * Return the backing int array of this property's IndexedDataStore. The array may be
51 * longer than necessary for the number of components in the system. Data can be
52 * accessed for a component directly using the component's index.
53 *
54 * @return The int data for all packed properties that this property has been packed
55 * with
56 */
57 public int[] getIndexedData() {
58 return data;
59 }
60
61 /**
62 * Get the value stored in this property for the given component index.
63 *
64 * @param componentIndex The component's index
65 *
66 * @return The object at the given offset for the given component
67 *
68 * @throws ArrayIndexOutOfBoundsException if the componentIndex is invalid
69 */
70 public int get(int componentIndex) {
71 return data[componentIndex];
72 }
73
74 /**
75 * Store <var>val</var> in this property for the given component index.
76 *
77 * @param componentIndex The index of the component being modified
78 * @param val The value to store, can be null
79 *
80 * @throws ArrayIndexOutOfBoundsException if the componentIndex is invalid
81 */
82 public void set(int componentIndex, int val) {
83 data[componentIndex] = val;
84 }
85
86 @Override
87 public void swap(int a, int b) {
88 int t = data[a];
89 data[a] = data[b];
90 data[b] = t;
91 }
92
93 @Override
94 public int getCapacity() {
95 return data.length;
96 }
97
98 @Override
99 public void setCapacity(int size) {
100 data = Arrays.copyOf(data, size);
101 }
102
103 /**
104 * Factory to create IntProperties. Properties annotated with DefaultInt will use that
105 * value as the default for all components.
106 *
107 * @author Michael Ludwig
108 */
109 public static class Factory implements PropertyFactory<IntProperty> {
110 private final int defaultValue;
111 private final Clone.Policy policy;
112
113 public Factory(Attributes attrs) {
114 defaultValue = attrs.hasAttribute(DefaultInt.class) ? attrs
115 .getAttribute(DefaultInt.class).value() : 0;
116 policy = attrs.hasAttribute(Clone.class) ? attrs.getAttribute(Clone.class)
117 .value()
118 : Clone.Policy.JAVA_DEFAULT;
119 }
120
121 public Factory(int defaultValue) {
122 this.defaultValue = defaultValue;
123 policy = Clone.Policy.JAVA_DEFAULT;
124 }
125
126 @Override
127 public IntProperty create() {
128 return new IntProperty();
129 }
130
131 @Override
132 public void setDefaultValue(IntProperty property, int index) {
133 property.set(index, defaultValue);
134 }
135
136 @Override
137 public void clone(IntProperty src, int srcIndex, IntProperty dst, int dstIndex) {
138 switch (policy) {
139 case DISABLE:
140 // assign default value
141 setDefaultValue(dst, dstIndex);
142 break;
143 case INVOKE_CLONE:
144 // fall through, since default implementation of INVOKE_CLONE is to
145 // just function like JAVA_DEFAULT
146 case JAVA_DEFAULT:
147 dst.set(dstIndex, src.get(srcIndex));
148 break;
149 default:
150 throw new UnsupportedOperationException(
151 "Enum value not supported: " + policy);
152 }
153 }
154 }
155
156 /**
157 * Default int attribute for properties.
158 *
159 * @author Michael Ludwig
160 */
161 @Attribute
162 @Retention(RetentionPolicy.RUNTIME)
163 public static @interface DefaultInt {
164 int value();
165 }
166 }