// 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_