| // Copyright 2008 Google Inc. |
| // Author: Lincoln Smith |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // There are two different representations of a Code Table's contents: |
| // VCDiffCodeTableData is the same as the format given in section 7 |
| // of the RFC, and is used for transmission and decoding. However, |
| // on the encoding side, it is useful to have a representation that |
| // can map efficiently from delta instructions to opcodes: |
| // VCDiffInstructionMap. A VCDiffInstructionMap is constructed |
| // using a VCDiffCodeTableData. For a custom code table, it is recommended |
| // that the VCDiffCodeTableData be defined as a static struct and that the |
| // VCDiffInstructionMap be a static pointer that gets initialized only once. |
| |
| #ifndef OPEN_VCDIFF_INSTRUCTION_MAP_H_ |
| #define OPEN_VCDIFF_INSTRUCTION_MAP_H_ |
| |
| #include <config.h> |
| #include "codetable.h" |
| #include "vcdiff_defs.h" |
| |
| namespace open_vcdiff { |
| |
| // An alternate representation of the data in a VCDiffCodeTableData that |
| // optimizes for fast encoding, that is, for taking a delta instruction |
| // inst (also known as instruction type), size, and mode and arriving at |
| // the corresponding opcode. |
| // |
| class VCDiffInstructionMap { |
| public: |
| // Create a VCDiffInstructionMap from the information in code_table_data. |
| // Does not save a pointer to code_table_data after using its contents |
| // to create the instruction->opcode mappings. The caller *must* have |
| // verified that code_table_data->Validate() returned true before |
| // attempting to use this constructor. |
| // max_mode is the maximum value for the mode of a COPY instruction. |
| // |
| VCDiffInstructionMap(const VCDiffCodeTableData& code_table_data, |
| unsigned char max_mode); |
| |
| static VCDiffInstructionMap* GetDefaultInstructionMap(); |
| |
| // Finds an opcode that has the given inst, size, and mode for its first |
| // instruction and NOOP for its second instruction (or vice versa.) |
| // Returns kNoOpcode if the code table does not have any matching |
| // opcode. Otherwise, returns an opcode value between 0 and 255. |
| // |
| // If this function returns kNoOpcode for size > 0, the caller will |
| // usually want to try again with size == 0 to find an opcode that |
| // doesn't have a fixed size value. |
| // |
| // If this function returns kNoOpcode for size == 0, it is an error condition, |
| // because any code table that passed the Validate() check should have a way |
| // of expressing all combinations of inst and mode with size=0. |
| // |
| OpcodeOrNone LookupFirstOpcode(unsigned char inst, |
| unsigned char size, |
| unsigned char mode) const { |
| return first_instruction_map_.Lookup(inst, size, mode); |
| } |
| |
| // Given a first opcode (presumed to have been returned by a previous call to |
| // lookupFirstOpcode), finds an opcode that has the same first instruction as |
| // the first opcode, and has the given inst, size, and mode for its second |
| // instruction. |
| // |
| // If this function returns kNoOpcode for size > 0, the caller will |
| // usually want to try again with size == 0 to find an opcode that |
| // doesn't have a fixed size value. |
| // |
| OpcodeOrNone LookupSecondOpcode(unsigned char first_opcode, |
| unsigned char inst, |
| unsigned char size, |
| unsigned char mode) const { |
| return second_instruction_map_.Lookup(first_opcode, inst, size, mode); |
| } |
| |
| private: |
| // Data structure used to implement LookupFirstOpcode efficiently. |
| // |
| class FirstInstructionMap { |
| public: |
| FirstInstructionMap(int num_insts_and_modes, int max_size_1); |
| ~FirstInstructionMap(); |
| |
| void Add(unsigned char inst, |
| unsigned char size, |
| unsigned char mode, |
| unsigned char opcode) { |
| OpcodeOrNone* opcode_slot = &first_opcodes_[inst + mode][size]; |
| if (*opcode_slot == kNoOpcode) { |
| *opcode_slot = opcode; |
| } |
| } |
| |
| // See comments for LookupFirstOpcode, above. |
| // |
| OpcodeOrNone Lookup(unsigned char inst, |
| unsigned char size, |
| unsigned char mode) const { |
| int inst_mode = (inst == VCD_COPY) ? (inst + mode) : inst; |
| if (size > max_size_1_) { |
| return kNoOpcode; |
| } |
| // Lookup specific-sized opcode |
| return first_opcodes_[inst_mode][size]; |
| } |
| |
| private: |
| // The number of possible combinations of inst (a VCDiffInstructionType) and |
| // mode. Since the mode is only used for COPY instructions, this number |
| // is not (number of VCDiffInstructionType values) * (number of modes), but |
| // rather (number of VCDiffInstructionType values other than VCD_COPY) |
| // + (number of COPY modes). |
| // |
| // Compressing inst and mode into a single integer relies on |
| // VCD_COPY being the last instruction type. The inst+mode values are: |
| // 0 (NOOP), 1 (ADD), 2 (RUN), 3 (COPY mode 0), 4 (COPY mode 1), ... |
| // |
| const int num_instruction_type_modes_; |
| |
| // The maximum value of a size1 element in code_table_data |
| // |
| const int max_size_1_; |
| |
| // There are two levels to first_opcodes_: |
| // 1) A dynamically-allocated pointer array of size |
| // num_instruction_type_modes_ (one element for each combination of inst |
| // and mode.) Every element of this array is non-NULL and contains |
| // a pointer to: |
| // 2) A dynamically-allocated array of OpcodeOrNone values, with one element |
| // for each possible first instruction size (size1) in the code table. |
| // (In the default code table, for example, the maximum size used is 18, |
| // so these arrays would have 19 elements representing values 0 |
| // through 18.) |
| // |
| OpcodeOrNone** first_opcodes_; |
| |
| // Making these private avoids implicit copy constructor |
| // and assignment operator |
| FirstInstructionMap(const FirstInstructionMap&); // NOLINT |
| void operator=(const FirstInstructionMap&); |
| } first_instruction_map_; |
| |
| // Data structure used to implement LookupSecondOpcode efficiently. |
| // |
| class SecondInstructionMap { |
| public: |
| SecondInstructionMap(int num_insts_and_modes, int max_size_2); |
| ~SecondInstructionMap(); |
| void Add(unsigned char first_opcode, |
| unsigned char inst, |
| unsigned char size, |
| unsigned char mode, |
| unsigned char second_opcode); |
| |
| // See comments for LookupSecondOpcode, above. |
| OpcodeOrNone Lookup(unsigned char first_opcode, |
| unsigned char inst, |
| unsigned char size, |
| unsigned char mode) const; |
| private: |
| // See the member of the same name in FirstInstructionMap. |
| const int num_instruction_type_modes_; |
| |
| // The maximum value of a size2 element in code_table_data |
| const int max_size_2_; |
| |
| // There are three levels to second_opcodes_: |
| // 1) A statically-allocated pointer array with one element |
| // for each possible opcode. Each element can be NULL, or can point to: |
| // 2) A dynamically-allocated pointer array of size |
| // num_instruction_type_modes_ (one element for each combination of inst |
| // and mode.) Each element can be NULL, or can point to: |
| // 3) A dynamically-allocated array with one element for each possible |
| // second instruction size in the code table. (In the default code |
| // table, for example, the maximum size used is 6, so these arrays would |
| // have 7 elements representing values 0 through 6.) |
| // |
| OpcodeOrNone** second_opcodes_[VCDiffCodeTableData::kCodeTableSize]; |
| |
| // Making these private avoids implicit copy constructor |
| // and assignment operator |
| SecondInstructionMap(const SecondInstructionMap&); // NOLINT |
| void operator=(const SecondInstructionMap&); |
| } second_instruction_map_; |
| |
| static VCDiffInstructionMap* default_instruction_map; |
| |
| // Making these private avoids implicit copy constructor & assignment operator |
| VCDiffInstructionMap(const VCDiffInstructionMap&); // NOLINT |
| void operator=(const VCDiffInstructionMap&); |
| }; |
| |
| }; // namespace open_vcdiff |
| |
| #endif // OPEN_VCDIFF_INSTRUCTION_MAP_H_ |