View Javadoc

1   /*
2    * Copyright  2000-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License"); 
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License. 
15   *
16   */
17  package org.apache.bcel.generic;
18  
19  /*** 
20   * SWITCH - Branch depending on int value, generates either LOOKUPSWITCH or
21   * TABLESWITCH instruction, depending on whether the match values (int[]) can be
22   * sorted with no gaps between the numbers.
23   *
24   * @version $Id: SWITCH.java 386056 2006-03-15 11:31:56Z tcurdt $
25   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
26   */
27  public final class SWITCH implements CompoundInstruction {
28  
29      private int[] match;
30      private InstructionHandle[] targets;
31      private Select instruction;
32      private int match_length;
33  
34  
35      /***
36       * Template for switch() constructs. If the match array can be
37       * sorted in ascending order with gaps no larger than max_gap
38       * between the numbers, a TABLESWITCH instruction is generated, and
39       * a LOOKUPSWITCH otherwise. The former may be more efficient, but
40       * needs more space.
41       * 
42       * Note, that the key array always will be sorted, though we leave
43       * the original arrays unaltered.
44       *
45       * @param match array of match values (case 2: ... case 7: ..., etc.)
46       * @param targets the instructions to be branched to for each case
47       * @param target the default target
48       * @param max_gap maximum gap that may between case branches
49       */
50      public SWITCH(int[] match, InstructionHandle[] targets, InstructionHandle target, int max_gap) {
51          this.match = (int[]) match.clone();
52          this.targets = (InstructionHandle[]) targets.clone();
53          if ((match_length = match.length) < 2) {
54              instruction = new TABLESWITCH(match, targets, target);
55          } else {
56              sort(0, match_length - 1);
57              if (matchIsOrdered(max_gap)) {
58                  fillup(max_gap, target);
59                  instruction = new TABLESWITCH(this.match, this.targets, target);
60              } else {
61                  instruction = new LOOKUPSWITCH(this.match, this.targets, target);
62              }
63          }
64      }
65  
66  
67      public SWITCH(int[] match, InstructionHandle[] targets, InstructionHandle target) {
68          this(match, targets, target, 1);
69      }
70  
71  
72      private final void fillup( int max_gap, InstructionHandle target ) {
73          int max_size = match_length + match_length * max_gap;
74          int[] m_vec = new int[max_size];
75          InstructionHandle[] t_vec = new InstructionHandle[max_size];
76          int count = 1;
77          m_vec[0] = match[0];
78          t_vec[0] = targets[0];
79          for (int i = 1; i < match_length; i++) {
80              int prev = match[i - 1];
81              int gap = match[i] - prev;
82              for (int j = 1; j < gap; j++) {
83                  m_vec[count] = prev + j;
84                  t_vec[count] = target;
85                  count++;
86              }
87              m_vec[count] = match[i];
88              t_vec[count] = targets[i];
89              count++;
90          }
91          match = new int[count];
92          targets = new InstructionHandle[count];
93          System.arraycopy(m_vec, 0, match, 0, count);
94          System.arraycopy(t_vec, 0, targets, 0, count);
95      }
96  
97  
98      /***
99       * Sort match and targets array with QuickSort.
100      */
101     private final void sort( int l, int r ) {
102         int i = l, j = r;
103         int h, m = match[(l + r) / 2];
104         InstructionHandle h2;
105         do {
106             while (match[i] < m) {
107                 i++;
108             }
109             while (m < match[j]) {
110                 j--;
111             }
112             if (i <= j) {
113                 h = match[i];
114                 match[i] = match[j];
115                 match[j] = h; // Swap elements
116                 h2 = targets[i];
117                 targets[i] = targets[j];
118                 targets[j] = h2; // Swap instructions, too
119                 i++;
120                 j--;
121             }
122         } while (i <= j);
123         if (l < j) {
124             sort(l, j);
125         }
126         if (i < r) {
127             sort(i, r);
128         }
129     }
130 
131 
132     /***
133      * @return match is sorted in ascending order with no gap bigger than max_gap?
134      */
135     private final boolean matchIsOrdered( int max_gap ) {
136         for (int i = 1; i < match_length; i++) {
137             if (match[i] - match[i - 1] > max_gap) {
138                 return false;
139             }
140         }
141         return true;
142     }
143 
144 
145     public final InstructionList getInstructionList() {
146         return new InstructionList(instruction);
147     }
148 
149 
150     public final Instruction getInstruction() {
151         return instruction;
152     }
153 }