browser/components/translation/cld2/internal/offsetmap.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright 2013 Google Inc. All Rights Reserved.
michael@0 2 //
michael@0 3 // Licensed under the Apache License, Version 2.0 (the "License");
michael@0 4 // you may not use this file except in compliance with the License.
michael@0 5 // You may obtain a copy of the License at
michael@0 6 //
michael@0 7 // http://www.apache.org/licenses/LICENSE-2.0
michael@0 8 //
michael@0 9 // Unless required by applicable law or agreed to in writing, software
michael@0 10 // distributed under the License is distributed on an "AS IS" BASIS,
michael@0 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 12 // See the License for the specific language governing permissions and
michael@0 13 // limitations under the License.
michael@0 14
michael@0 15 //
michael@0 16 // Author: dsites@google.com (Dick Sites)
michael@0 17 //
michael@0 18 //
michael@0 19
michael@0 20 #include "offsetmap.h"
michael@0 21
michael@0 22 #include <string.h> // for strcmp
michael@0 23 #include <stdio.h> // for fprintf, stderr, fclose, etc
michael@0 24 #include <algorithm> // for min
michael@0 25
michael@0 26 using namespace std;
michael@0 27
michael@0 28 namespace CLD2 {
michael@0 29
michael@0 30 // Constructor, destructor
michael@0 31 OffsetMap::OffsetMap() {
michael@0 32 Clear();
michael@0 33 }
michael@0 34
michael@0 35 OffsetMap::~OffsetMap() {
michael@0 36 }
michael@0 37
michael@0 38 // Clear the map
michael@0 39 // After:
michael@0 40 // next_diff_sub_ is 0
michael@0 41 // Windows are the a and a' ranges covered by diffs_[next_diff_sub_-1]
michael@0 42 // which is a fake range of width 0 mapping 0=>0
michael@0 43 void OffsetMap::Clear() {
michael@0 44 diffs_.clear();
michael@0 45 pending_op_ = COPY_OP;
michael@0 46 pending_length_ = 0;
michael@0 47 next_diff_sub_ = 0;
michael@0 48 current_lo_aoffset_ = 0;
michael@0 49 current_hi_aoffset_ = 0;
michael@0 50 current_lo_aprimeoffset_ = 0;
michael@0 51 current_hi_aprimeoffset_ = 0;
michael@0 52 current_diff_ = 0;
michael@0 53 max_aoffset_ = 0; // Largest seen so far
michael@0 54 max_aprimeoffset_ = 0; // Largest seen so far
michael@0 55 }
michael@0 56
michael@0 57 static inline char OpPart(const char c) {
michael@0 58 return (c >> 6) & 3;
michael@0 59 }
michael@0 60 static inline char LenPart(const char c) {
michael@0 61 return c & 0x3f;
michael@0 62 }
michael@0 63
michael@0 64 // Print map to file, for debugging
michael@0 65 void OffsetMap::Printmap(const char* filename) {
michael@0 66 FILE* fout;
michael@0 67 bool needs_close = false;
michael@0 68 if (strcmp(filename, "stdout") == 0) {
michael@0 69 fout = stdout;
michael@0 70 } else if (strcmp(filename, "stderr") == 0) {
michael@0 71 fout = stderr;
michael@0 72 } else {
michael@0 73 fout = fopen(filename, "w");
michael@0 74 needs_close = true;
michael@0 75 }
michael@0 76 if (fout == NULL) {
michael@0 77 fprintf(stderr, "%s did not open\n", filename);
michael@0 78 return;
michael@0 79 }
michael@0 80
michael@0 81 Flush(); // Make sure any pending entry gets printed
michael@0 82 fprintf(fout, "Offsetmap: %ld bytes\n", diffs_.size());
michael@0 83 for (int i = 0; i < static_cast<int>(diffs_.size()); ++i) {
michael@0 84 fprintf(fout, "%c%02d ", "&=+-"[OpPart(diffs_[i])], LenPart(diffs_[i]));
michael@0 85 if ((i % 20) == 19) {fprintf(fout, "\n");}
michael@0 86 }
michael@0 87 fprintf(fout, "\n");
michael@0 88 if (needs_close) {
michael@0 89 fclose(fout);
michael@0 90 }
michael@0 91 }
michael@0 92
michael@0 93 // Reset to offset 0
michael@0 94 void OffsetMap::Reset() {
michael@0 95 MaybeFlushAll();
michael@0 96
michael@0 97 next_diff_sub_ = 0;
michael@0 98 current_lo_aoffset_ = 0;
michael@0 99 current_hi_aoffset_ = 0;
michael@0 100 current_lo_aprimeoffset_ = 0;
michael@0 101 current_hi_aprimeoffset_ = 0;
michael@0 102 current_diff_ = 0;
michael@0 103 }
michael@0 104
michael@0 105 // Add to mapping from A to A', specifying how many next bytes are
michael@0 106 // identical in A and A'
michael@0 107 void OffsetMap::Copy(int bytes) {
michael@0 108 if (bytes == 0) {return;}
michael@0 109 max_aoffset_ += bytes; // Largest seen so far
michael@0 110 max_aprimeoffset_ += bytes; // Largest seen so far
michael@0 111 if (pending_op_ == COPY_OP) {
michael@0 112 pending_length_ += bytes;
michael@0 113 } else {
michael@0 114 Flush();
michael@0 115 pending_op_ = COPY_OP;
michael@0 116 pending_length_ = bytes;
michael@0 117 }
michael@0 118 }
michael@0 119
michael@0 120 // Add to mapping from A to A', specifying how many next bytes are
michael@0 121 // inserted in A' while not advancing in A at all
michael@0 122 void OffsetMap::Insert(int bytes){
michael@0 123 if (bytes == 0) {return;}
michael@0 124 max_aprimeoffset_ += bytes; // Largest seen so far
michael@0 125 if (pending_op_ == INSERT_OP) {
michael@0 126 pending_length_ += bytes;
michael@0 127 } else if ((bytes == 1) &&
michael@0 128 (pending_op_ == DELETE_OP) && (pending_length_ == 1)) {
michael@0 129 // Special-case exactly delete(1) insert(1) +> copy(1);
michael@0 130 // all others backmap inserts to after deletes
michael@0 131 pending_op_ = COPY_OP;
michael@0 132 } else {
michael@0 133 Flush();
michael@0 134 pending_op_ = INSERT_OP;
michael@0 135 pending_length_ = bytes;
michael@0 136 }
michael@0 137 }
michael@0 138
michael@0 139 // Add to mapping from A to A', specifying how many next bytes are
michael@0 140 // deleted from A while not advancing in A' at all
michael@0 141 void OffsetMap::Delete(int bytes){
michael@0 142 if (bytes == 0) {return;}
michael@0 143 max_aoffset_ += bytes; // Largest seen so far
michael@0 144 if (pending_op_ == DELETE_OP) {
michael@0 145 pending_length_ += bytes;
michael@0 146 } else if ((bytes == 1) &&
michael@0 147 (pending_op_ == INSERT_OP) && (pending_length_ == 1)) {
michael@0 148 // Special-case exactly insert(1) delete(1) => copy(1);
michael@0 149 // all others backmap deletes to after insertss
michael@0 150 pending_op_ = COPY_OP;
michael@0 151 } else {
michael@0 152 Flush();
michael@0 153 pending_op_ = DELETE_OP;
michael@0 154 pending_length_ = bytes;
michael@0 155 }
michael@0 156 }
michael@0 157
michael@0 158 void OffsetMap::Flush() {
michael@0 159 if (pending_length_ == 0) {
michael@0 160 return;
michael@0 161 }
michael@0 162 // We may be emitting a copy op just after a copy op because +1 -1 cancelled
michael@0 163 // inbetween. If the lengths don't need a prefix byte, combine them
michael@0 164 if ((pending_op_ == COPY_OP) && !diffs_.empty()) {
michael@0 165 char c = diffs_[diffs_.size() - 1];
michael@0 166 MapOp prior_op = static_cast<MapOp>(OpPart(c));
michael@0 167 int prior_len = LenPart(c);
michael@0 168 if ((prior_op == COPY_OP) && ((prior_len + pending_length_) <= 0x3f)) {
michael@0 169 diffs_[diffs_.size() - 1] += pending_length_;
michael@0 170 pending_length_ = 0;
michael@0 171 return;
michael@0 172 }
michael@0 173 }
michael@0 174 if (pending_length_ > 0x3f) {
michael@0 175 bool non_zero_emitted = false;
michael@0 176 for (int shift = 30; shift > 0; shift -= 6) {
michael@0 177 int prefix = (pending_length_ >> shift) & 0x3f;
michael@0 178 if ((prefix > 0) || non_zero_emitted) {
michael@0 179 Emit(PREFIX_OP, prefix);
michael@0 180 non_zero_emitted = true;
michael@0 181 }
michael@0 182 }
michael@0 183 }
michael@0 184 Emit(pending_op_, pending_length_ & 0x3f);
michael@0 185 pending_length_ = 0;
michael@0 186 }
michael@0 187
michael@0 188
michael@0 189 // Add one more entry to copy one byte off the end, then flush
michael@0 190 void OffsetMap::FlushAll() {
michael@0 191 Copy(1);
michael@0 192 Flush();
michael@0 193 }
michael@0 194
michael@0 195 // Flush all if necessary
michael@0 196 void OffsetMap::MaybeFlushAll() {
michael@0 197 if ((0 < pending_length_) || diffs_.empty()) {
michael@0 198 FlushAll();
michael@0 199 }
michael@0 200 }
michael@0 201
michael@0 202 // Len may be 0, for example as the low piece of length=64
michael@0 203 void OffsetMap::Emit(MapOp op, int len) {
michael@0 204 char c = (static_cast<char>(op) << 6) | (len & 0x3f);
michael@0 205 diffs_.push_back(c);
michael@0 206 }
michael@0 207
michael@0 208 void OffsetMap::DumpString() {
michael@0 209 for (int i = 0; i < static_cast<int>(diffs_.size()); ++i) {
michael@0 210 fprintf(stderr, "%c%02d ", "&=+-"[OpPart(diffs_[i])], LenPart(diffs_[i]));
michael@0 211 }
michael@0 212 fprintf(stderr, "\n");
michael@0 213
michael@0 214 // Print running table of correspondences
michael@0 215 fprintf(stderr, " op A => A' (A forward-maps to A')\n");
michael@0 216 int aoffset = 0;
michael@0 217 int aprimeoffset = 0;
michael@0 218 int length = 0;
michael@0 219 for (int i = 0; i < static_cast<int>(diffs_.size()); ++i) {
michael@0 220 char c = diffs_[i];
michael@0 221 MapOp op = static_cast<MapOp>(OpPart(c));
michael@0 222 int len = LenPart(c);
michael@0 223 length = (length << 6) + len;
michael@0 224 if (op == COPY_OP) {
michael@0 225 aoffset += length;
michael@0 226 aprimeoffset += length;
michael@0 227 length = 0;
michael@0 228 } else if (op == INSERT_OP) {
michael@0 229 aoffset += 0;
michael@0 230 aprimeoffset += length;
michael@0 231 length = 0;
michael@0 232 } else if (op == DELETE_OP) {
michael@0 233 aoffset += length;
michael@0 234 aprimeoffset += 0;
michael@0 235 length = 0;
michael@0 236 } else { // (op == PREFIX_OP)
michael@0 237 // Do nothing else
michael@0 238 }
michael@0 239 fprintf(stderr, "[%3d] %c%02d %6d %6d%s\n",
michael@0 240 i, "&=+-"[op], len,
michael@0 241 aoffset, aprimeoffset,
michael@0 242 (next_diff_sub_ == i) ? " <==next_diff_sub_" : "");
michael@0 243
michael@0 244 }
michael@0 245 fprintf(stderr, "\n");
michael@0 246 }
michael@0 247
michael@0 248 void OffsetMap::DumpWindow() {
michael@0 249 fprintf(stderr, "DumpWindow(A => A'): max_aoffset_ = %d, "
michael@0 250 "max_aprimeoffset_ = %d, next_diff_sub_ = %d<br>\n",
michael@0 251 max_aoffset_, max_aprimeoffset_, next_diff_sub_);
michael@0 252 fprintf(stderr, "A [%u..%u)\n",
michael@0 253 current_lo_aoffset_, current_hi_aoffset_);
michael@0 254 fprintf(stderr, "A' [%u..%u)\n",
michael@0 255 current_lo_aprimeoffset_, current_hi_aprimeoffset_);
michael@0 256 fprintf(stderr, " diff = %d\n", current_diff_);
michael@0 257 DumpString();
michael@0 258 }
michael@0 259
michael@0 260 //----------------------------------------------------------------------------//
michael@0 261 // The guts of the 2013 design //
michael@0 262 // If there are three ranges a b c in diffs_, we can be in one of five //
michael@0 263 // states: LEFT of a, in ranges a b c, or RIGHT of c //
michael@0 264 // In each state, there are windows A[Alo..Ahi), A'[A'lo..A'hi) and diffs_ //
michael@0 265 // position next_diff_sub_ //
michael@0 266 // There also are mapping constants max_aoffset_ and max_aprimeoffset_ //
michael@0 267 // If LEFT, Alo=Ahi=0, A'lo=A'hi=0 and next_diff_sub_=0 //
michael@0 268 // If RIGHT, Alo=Ahi=max_aoffset_, A'lo=A'hi=max_aprimeoffset_ and //
michael@0 269 // next_diff_sub_=diffs_.size() //
michael@0 270 // Otherwise, at least one of A[) and A'[) is non-empty and the first bytes //
michael@0 271 // correspond to each other. If range i is active, next_diff_sub_ is at //
michael@0 272 // the first byte of range i+1. Because of the length-prefix operator, //
michael@0 273 // an individual range item in diffs_ may be multiple bytes //
michael@0 274 // In all cases aprimeoffset = aoffset + current_diff_ //
michael@0 275 // i.e. current_diff_ = aprimeoffset - aoffset //
michael@0 276 // //
michael@0 277 // In the degenerate case of diffs_.empty(), there are only two states //
michael@0 278 // LEFT and RIGHT and the mapping is the identity mapping. //
michael@0 279 // The initial state is LEFT. //
michael@0 280 // It is an error to move left into LEFT or right into RIGHT, but the code //
michael@0 281 // below is robust in these cases. //
michael@0 282 //----------------------------------------------------------------------------//
michael@0 283
michael@0 284 void OffsetMap::SetLeft() {
michael@0 285 current_lo_aoffset_ = 0;
michael@0 286 current_hi_aoffset_ = 0;
michael@0 287 current_lo_aprimeoffset_ = 0;
michael@0 288 current_hi_aprimeoffset_ = 0;
michael@0 289 current_diff_ = 0;
michael@0 290 next_diff_sub_ = 0;
michael@0 291 }
michael@0 292
michael@0 293 void OffsetMap::SetRight() {
michael@0 294 current_lo_aoffset_ = max_aoffset_;
michael@0 295 current_hi_aoffset_ = max_aoffset_;
michael@0 296 current_lo_aprimeoffset_ = max_aprimeoffset_;
michael@0 297 current_hi_aprimeoffset_ = max_aprimeoffset_;
michael@0 298 current_diff_ = max_aprimeoffset_ - max_aoffset_;
michael@0 299 next_diff_sub_ = 0;
michael@0 300 }
michael@0 301
michael@0 302 // Back up over previous range, 1..5 bytes
michael@0 303 // Return subscript at the beginning of that. Pins at 0
michael@0 304 int OffsetMap::Backup(int sub) {
michael@0 305 if (sub <= 0) {return 0;}
michael@0 306 --sub;
michael@0 307 while ((0 < sub) &&
michael@0 308 (static_cast<MapOp>(OpPart(diffs_[sub - 1]) == PREFIX_OP))) {
michael@0 309 --sub;
michael@0 310 }
michael@0 311 return sub;
michael@0 312 }
michael@0 313
michael@0 314 // Parse next range, 1..5 bytes
michael@0 315 // Return subscript just off the end of that
michael@0 316 int OffsetMap::ParseNext(int sub, MapOp* op, int* length) {
michael@0 317 *op = PREFIX_OP;
michael@0 318 *length = 0;
michael@0 319 char c;
michael@0 320 while ((sub < static_cast<int>(diffs_.size())) && (*op == PREFIX_OP)) {
michael@0 321 c = diffs_[sub++];
michael@0 322 *op = static_cast<MapOp>(OpPart(c));
michael@0 323 int len = LenPart(c);
michael@0 324 *length = (*length << 6) + len;
michael@0 325 }
michael@0 326 // If mal-formed or in RIGHT, this will return with op = PREFIX_OP
michael@0 327 // Mal-formed can include a trailing prefix byte with no following op
michael@0 328 return sub;
michael@0 329 }
michael@0 330
michael@0 331 // Parse previous range, 1..5 bytes
michael@0 332 // Return current subscript
michael@0 333 int OffsetMap::ParsePrevious(int sub, MapOp* op, int* length) {
michael@0 334 sub = Backup(sub);
michael@0 335 return ParseNext(sub, op, length);
michael@0 336 }
michael@0 337
michael@0 338 // Quick debugging dump; does not parse multi-byte items, so just length & 0x3f
michael@0 339 void OffsetMap::PrintPosition(const char* str) {
michael@0 340 MapOp op = PREFIX_OP;
michael@0 341 int length = 0;
michael@0 342 if ((0 < next_diff_sub_) && (next_diff_sub_ <= static_cast<int>(diffs_.size()))) {
michael@0 343 op = static_cast<MapOp>(OpPart(diffs_[next_diff_sub_ - 1]));
michael@0 344 length = LenPart(diffs_[next_diff_sub_ - 1]);
michael@0 345 }
michael@0 346 fprintf(stderr, "%s[%d] %c%02d = A[%d..%d) ==> A'[%d..%d)\n",
michael@0 347 str,
michael@0 348 next_diff_sub_, "&=+-"[op], length,
michael@0 349 current_lo_aoffset_, current_hi_aoffset_,
michael@0 350 current_lo_aprimeoffset_, current_hi_aprimeoffset_);
michael@0 351 }
michael@0 352
michael@0 353 // Move active window one range to the right
michael@0 354 // Return true if move was OK
michael@0 355 bool OffsetMap::MoveRight() {
michael@0 356 // If at last range or RIGHT, set to RIGHT, return error
michael@0 357 if (next_diff_sub_ >= static_cast<int>(diffs_.size())) {
michael@0 358 SetRight();
michael@0 359 return false;
michael@0 360 }
michael@0 361 // Actually OK to move right
michael@0 362 MapOp op;
michael@0 363 int length;
michael@0 364 bool retval = true;
michael@0 365 // If mal-formed or in RIGHT, this will return with op = PREFIX_OP
michael@0 366 next_diff_sub_ = ParseNext(next_diff_sub_, &op, &length);
michael@0 367
michael@0 368 current_lo_aoffset_ = current_hi_aoffset_;
michael@0 369 current_lo_aprimeoffset_ = current_hi_aprimeoffset_;
michael@0 370 if (op == COPY_OP) {
michael@0 371 current_hi_aoffset_ = current_lo_aoffset_ + length;
michael@0 372 current_hi_aprimeoffset_ = current_lo_aprimeoffset_ + length;
michael@0 373 } else if (op == INSERT_OP) {
michael@0 374 current_hi_aoffset_ = current_lo_aoffset_ + 0;
michael@0 375 current_hi_aprimeoffset_ = current_lo_aprimeoffset_ + length;
michael@0 376 } else if (op == DELETE_OP) {
michael@0 377 current_hi_aoffset_ = current_lo_aoffset_ + length;
michael@0 378 current_hi_aprimeoffset_ = current_lo_aprimeoffset_ + 0;
michael@0 379 } else {
michael@0 380 SetRight();
michael@0 381 retval = false;
michael@0 382 }
michael@0 383 current_diff_ = current_lo_aprimeoffset_ - current_lo_aoffset_;
michael@0 384 return retval;
michael@0 385 }
michael@0 386
michael@0 387 // Move active window one range to the left
michael@0 388 // Return true if move was OK
michael@0 389 bool OffsetMap::MoveLeft() {
michael@0 390 // If at first range or LEFT, set to LEFT, return error
michael@0 391 if (next_diff_sub_ <= 0) {
michael@0 392 SetLeft();
michael@0 393 return false;
michael@0 394 }
michael@0 395 // Back up over current active window
michael@0 396 next_diff_sub_ = Backup(next_diff_sub_);
michael@0 397 if (next_diff_sub_ <= 0) {
michael@0 398 SetLeft();
michael@0 399 return false;
michael@0 400 }
michael@0 401 // Actually OK to move left
michael@0 402 MapOp op;
michael@0 403 int length;
michael@0 404 bool retval = true;
michael@0 405 // If mal-formed or in LEFT, this will return with op = PREFIX_OP
michael@0 406 next_diff_sub_ = ParsePrevious(next_diff_sub_, &op, &length);
michael@0 407
michael@0 408 current_hi_aoffset_ = current_lo_aoffset_;
michael@0 409 current_hi_aprimeoffset_ = current_lo_aprimeoffset_;
michael@0 410 if (op == COPY_OP) {
michael@0 411 current_lo_aoffset_ = current_hi_aoffset_ - length;
michael@0 412 current_lo_aprimeoffset_ = current_hi_aprimeoffset_ - length;
michael@0 413 } else if (op == INSERT_OP) {
michael@0 414 current_lo_aoffset_ = current_hi_aoffset_ - 0;
michael@0 415 current_lo_aprimeoffset_ = current_hi_aprimeoffset_ - length;
michael@0 416 } else if (op == DELETE_OP) {
michael@0 417 current_lo_aoffset_ = current_hi_aoffset_ - length;
michael@0 418 current_lo_aprimeoffset_ = current_hi_aprimeoffset_ - 0;
michael@0 419 } else {
michael@0 420 SetLeft();
michael@0 421 retval = false;
michael@0 422 }
michael@0 423 current_diff_ = current_lo_aprimeoffset_ - current_lo_aoffset_;
michael@0 424 return true;
michael@0 425 }
michael@0 426
michael@0 427 // Map an offset in A' to the corresponding offset in A
michael@0 428 int OffsetMap::MapBack(int aprimeoffset){
michael@0 429 MaybeFlushAll();
michael@0 430 if (aprimeoffset < 0) {return 0;}
michael@0 431 if (max_aprimeoffset_ <= aprimeoffset) {
michael@0 432 return (aprimeoffset - max_aprimeoffset_) + max_aoffset_;
michael@0 433 }
michael@0 434
michael@0 435 // If current_lo_aprimeoffset_ <= aprimeoffset < current_hi_aprimeoffset_,
michael@0 436 // use current mapping, else move window left/right
michael@0 437 bool ok = true;
michael@0 438 while (ok && (aprimeoffset < current_lo_aprimeoffset_)) {
michael@0 439 ok = MoveLeft();
michael@0 440 }
michael@0 441 while (ok && (current_hi_aprimeoffset_ <= aprimeoffset)) {
michael@0 442 ok = MoveRight();
michael@0 443 }
michael@0 444 // So now current_lo_aprimeoffset_ <= aprimeoffset < current_hi_aprimeoffset_
michael@0 445
michael@0 446 int aoffset = aprimeoffset - current_diff_;
michael@0 447 if (aoffset >= current_hi_aoffset_) {
michael@0 448 // A' is in an insert region, all bytes of which backmap to A=hi_aoffset_
michael@0 449 aoffset = current_hi_aoffset_;
michael@0 450 }
michael@0 451 return aoffset;
michael@0 452 }
michael@0 453
michael@0 454 // Map an offset in A to the corresponding offset in A'
michael@0 455 int OffsetMap::MapForward(int aoffset){
michael@0 456 MaybeFlushAll();
michael@0 457 if (aoffset < 0) {return 0;}
michael@0 458 if (max_aoffset_ <= aoffset) {
michael@0 459 return (aoffset - max_aoffset_) + max_aprimeoffset_;
michael@0 460 }
michael@0 461
michael@0 462 // If current_lo_aoffset_ <= aoffset < current_hi_aoffset_,
michael@0 463 // use current mapping, else move window left/right
michael@0 464 bool ok = true;
michael@0 465 while (ok && (aoffset < current_lo_aoffset_)) {
michael@0 466 ok = MoveLeft();
michael@0 467 }
michael@0 468 while (ok && (current_hi_aoffset_ <= aoffset)) {
michael@0 469 ok = MoveRight();
michael@0 470 }
michael@0 471
michael@0 472 int aprimeoffset = aoffset + current_diff_;
michael@0 473 if (aprimeoffset >= current_hi_aprimeoffset_) {
michael@0 474 // A is in a delete region, all bytes of which map to A'=hi_aprimeoffset_
michael@0 475 aprimeoffset = current_hi_aprimeoffset_;
michael@0 476 }
michael@0 477 return aprimeoffset;
michael@0 478 }
michael@0 479
michael@0 480
michael@0 481 // static
michael@0 482 bool OffsetMap::CopyInserts(OffsetMap* source, OffsetMap* dest) {
michael@0 483 bool ok = true;
michael@0 484 while (ok && (source->next_diff_sub_ != source->diffs_.size())) {
michael@0 485 ok = source->MoveRight();
michael@0 486 if (source->current_lo_aoffset_ != source->current_hi_aoffset_) {
michael@0 487 return false;
michael@0 488 }
michael@0 489 dest->Insert(
michael@0 490 source->current_hi_aprimeoffset_ - source->current_lo_aprimeoffset_);
michael@0 491 }
michael@0 492 return true;
michael@0 493 }
michael@0 494
michael@0 495 // static
michael@0 496 bool OffsetMap::CopyDeletes(OffsetMap* source, OffsetMap* dest) {
michael@0 497 bool ok = true;
michael@0 498 while (ok && (source->next_diff_sub_ != source->diffs_.size())) {
michael@0 499 ok = source->MoveRight();
michael@0 500 if (source->current_lo_aprimeoffset_ != source->current_hi_aprimeoffset_) {
michael@0 501 return false;
michael@0 502 }
michael@0 503 dest->Delete(source->current_hi_aoffset_ - source->current_lo_aoffset_);
michael@0 504 }
michael@0 505 return true;
michael@0 506 }
michael@0 507
michael@0 508 // static
michael@0 509 void OffsetMap::ComposeOffsetMap(
michael@0 510 OffsetMap* g, OffsetMap* f, OffsetMap* h) {
michael@0 511 h->Clear();
michael@0 512 f->Reset();
michael@0 513 g->Reset();
michael@0 514
michael@0 515 int lo = 0;
michael@0 516 for (;;) {
michael@0 517 // Consume delete operations in f. This moves A without moving
michael@0 518 // A' and A''.
michael@0 519 if (lo >= g->current_hi_aoffset_ && CopyInserts(g, h)) {
michael@0 520 if (lo >= f->current_hi_aprimeoffset_ && CopyDeletes(f, h)) {
michael@0 521 // fprintf(stderr,
michael@0 522 // "ComposeOffsetMap ERROR, f is longer than g.<br>\n");
michael@0 523 }
michael@0 524
michael@0 525 // FlushAll(), called by Reset(), MapForward() or MapBack(), has
michael@0 526 // added an extra COPY_OP to f and g, so this function has
michael@0 527 // composed an extra COPY_OP in h from those. To avoid
michael@0 528 // FlushAll() adds one more extra COPY_OP to h later, dispatch
michael@0 529 // Flush() right now.
michael@0 530 h->Flush();
michael@0 531 return;
michael@0 532 }
michael@0 533
michael@0 534 // Consume insert operations in g. This moves A'' without moving A
michael@0 535 // and A'.
michael@0 536 if (lo >= f->current_hi_aprimeoffset_) {
michael@0 537 if (!CopyDeletes(f, h)) {
michael@0 538 // fprintf(stderr,
michael@0 539 // "ComposeOffsetMap ERROR, g is longer than f.<br>\n");
michael@0 540 }
michael@0 541 }
michael@0 542
michael@0 543 // Compose one operation which moves A' from lo to hi.
michael@0 544 int hi = min(f->current_hi_aprimeoffset_, g->current_hi_aoffset_);
michael@0 545 if (f->current_lo_aoffset_ != f->current_hi_aoffset_ &&
michael@0 546 g->current_lo_aprimeoffset_ != g->current_hi_aprimeoffset_) {
michael@0 547 h->Copy(hi - lo);
michael@0 548 } else if (f->current_lo_aoffset_ != f->current_hi_aoffset_) {
michael@0 549 h->Delete(hi - lo);
michael@0 550 } else if (g->current_lo_aprimeoffset_ != g->current_hi_aprimeoffset_) {
michael@0 551 h->Insert(hi - lo);
michael@0 552 }
michael@0 553
michael@0 554 lo = hi;
michael@0 555 }
michael@0 556 }
michael@0 557
michael@0 558 // For testing only -- force a mapping
michael@0 559 void OffsetMap::StuffIt(const string& diffs,
michael@0 560 int max_aoffset, int max_aprimeoffset) {
michael@0 561 Clear();
michael@0 562 diffs_ = diffs;
michael@0 563 max_aoffset_ = max_aoffset;
michael@0 564 max_aprimeoffset_ = max_aprimeoffset;
michael@0 565 }
michael@0 566
michael@0 567
michael@0 568 } // namespace CLD2
michael@0 569

mercurial