this repo has no description
at trunk 790 lines 29 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "bytearray-builtins.h" 3 4#include "builtins.h" 5#include "bytes-builtins.h" 6#include "byteslike.h" 7#include "formatter-utils.h" 8#include "int-builtins.h" 9#include "runtime.h" 10#include "slice-builtins.h" 11#include "type-builtins.h" 12#include "unicode.h" 13 14namespace py { 15 16RawObject bytearrayAsBytes(Thread* thread, const Bytearray& array) { 17 HandleScope scope(thread); 18 Bytes bytes(&scope, array.items()); 19 return bytesSubseq(thread, bytes, 0, array.numItems()); 20} 21 22static const BuiltinAttribute kBytearrayAttributes[] = { 23 {ID(_bytearray__bytes), RawBytearray::kItemsOffset, 24 AttributeFlags::kHidden}, 25 {ID(_bytearray__num_items), RawBytearray::kNumItemsOffset, 26 AttributeFlags::kHidden}, 27}; 28 29static const BuiltinAttribute kBytearrayIteratorAttributes[] = { 30 {ID(_bytearray_iterator__iterable), RawBytearrayIterator::kIterableOffset, 31 AttributeFlags::kHidden}, 32 {ID(_bytearray_iterator__index), RawBytearrayIterator::kIndexOffset, 33 AttributeFlags::kHidden}, 34}; 35 36void initializeBytearrayTypes(Thread* thread) { 37 addBuiltinType(thread, ID(bytearray), LayoutId::kBytearray, 38 /*superclass_id=*/LayoutId::kObject, kBytearrayAttributes, 39 Bytearray::kSize, /*basetype=*/true); 40 41 addBuiltinType(thread, ID(bytearray_iterator), LayoutId::kBytearrayIterator, 42 /*superclass_id=*/LayoutId::kObject, 43 kBytearrayIteratorAttributes, BytearrayIterator::kSize, 44 /*basetype=*/false); 45} 46 47RawObject METH(bytearray, __add__)(Thread* thread, Arguments args) { 48 HandleScope scope(thread); 49 Object self_obj(&scope, args.get(0)); 50 Runtime* runtime = thread->runtime(); 51 if (!runtime->isInstanceOfBytearray(*self_obj)) { 52 return thread->raiseRequiresType(self_obj, ID(bytearray)); 53 } 54 Object other_obj(&scope, args.get(1)); 55 word other_len; 56 if (runtime->isInstanceOfBytearray(*other_obj)) { 57 Bytearray array(&scope, *other_obj); 58 other_len = array.numItems(); 59 other_obj = array.items(); 60 } else if (runtime->isInstanceOfBytes(*other_obj)) { 61 Bytes bytes(&scope, bytesUnderlying(*other_obj)); 62 other_len = bytes.length(); 63 other_obj = *bytes; 64 } else { 65 return thread->raiseWithFmt( 66 LayoutId::kTypeError, 67 "can only concatenate bytearray or bytes to bytearray"); 68 } 69 70 Bytearray self(&scope, *self_obj); 71 Bytes self_bytes(&scope, self.items()); 72 word self_len = self.numItems(); 73 Bytes other_bytes(&scope, *other_obj); 74 75 Bytearray result(&scope, runtime->newBytearray()); 76 runtime->bytearrayEnsureCapacity(thread, result, self_len + other_len); 77 runtime->bytearrayIadd(thread, result, self_bytes, self_len); 78 runtime->bytearrayIadd(thread, result, other_bytes, other_len); 79 return *result; 80} 81 82RawObject METH(bytearray, __eq__)(Thread* thread, Arguments args) { 83 Runtime* runtime = thread->runtime(); 84 HandleScope scope(thread); 85 Object self_obj(&scope, args.get(0)); 86 if (!runtime->isInstanceOfBytearray(*self_obj)) { 87 return thread->raiseRequiresType(self_obj, ID(bytearray)); 88 } 89 Bytearray self(&scope, *self_obj); 90 Object other_obj(&scope, args.get(1)); 91 word comparison; 92 if (runtime->isInstanceOfBytes(*other_obj)) { 93 Bytes other(&scope, bytesUnderlying(*other_obj)); 94 comparison = self.compare(*other, other.length()); 95 } else if (runtime->isInstanceOfBytearray(*other_obj)) { 96 Bytearray other(&scope, *other_obj); 97 Bytes other_bytes(&scope, other.items()); 98 comparison = self.compare(*other_bytes, other.numItems()); 99 } else { 100 // TODO(T38246066): allow any bytes-like object 101 return NotImplementedType::object(); 102 } 103 return Bool::fromBool(comparison == 0); 104} 105 106RawObject METH(bytearray, __ge__)(Thread* thread, Arguments args) { 107 Runtime* runtime = thread->runtime(); 108 HandleScope scope(thread); 109 Object self_obj(&scope, args.get(0)); 110 if (!runtime->isInstanceOfBytearray(*self_obj)) { 111 return thread->raiseRequiresType(self_obj, ID(bytearray)); 112 } 113 Bytearray self(&scope, *self_obj); 114 Object other_obj(&scope, args.get(1)); 115 word comparison; 116 if (runtime->isInstanceOfBytes(*other_obj)) { 117 Bytes other(&scope, bytesUnderlying(*other_obj)); 118 comparison = self.compare(*other, other.length()); 119 } else if (runtime->isInstanceOfBytearray(*other_obj)) { 120 Bytearray other(&scope, *other_obj); 121 Bytes other_bytes(&scope, other.items()); 122 comparison = self.compare(*other_bytes, other.numItems()); 123 } else { 124 // TODO(T38246066): allow any bytes-like object 125 return NotImplementedType::object(); 126 } 127 return Bool::fromBool(comparison >= 0); 128} 129 130RawObject METH(bytearray, __gt__)(Thread* thread, Arguments args) { 131 Runtime* runtime = thread->runtime(); 132 HandleScope scope(thread); 133 Object self_obj(&scope, args.get(0)); 134 if (!runtime->isInstanceOfBytearray(*self_obj)) { 135 return thread->raiseRequiresType(self_obj, ID(bytearray)); 136 } 137 Bytearray self(&scope, *self_obj); 138 Object other_obj(&scope, args.get(1)); 139 word comparison; 140 if (runtime->isInstanceOfBytes(*other_obj)) { 141 Bytes other(&scope, bytesUnderlying(*other_obj)); 142 comparison = self.compare(*other, other.length()); 143 } else if (runtime->isInstanceOfBytearray(*other_obj)) { 144 Bytearray other(&scope, *other_obj); 145 Bytes other_bytes(&scope, other.items()); 146 comparison = self.compare(*other_bytes, other.numItems()); 147 } else { 148 // TODO(T38246066): allow any bytes-like object 149 return NotImplementedType::object(); 150 } 151 return Bool::fromBool(comparison > 0); 152} 153 154RawObject METH(bytearray, __iadd__)(Thread* thread, Arguments args) { 155 HandleScope scope(thread); 156 Object self_obj(&scope, args.get(0)); 157 Runtime* runtime = thread->runtime(); 158 if (!runtime->isInstanceOfBytearray(*self_obj)) { 159 return thread->raiseRequiresType(self_obj, ID(bytearray)); 160 } 161 Bytearray self(&scope, *self_obj); 162 163 Object other_obj(&scope, args.get(1)); 164 Byteslike other(&scope, thread, *other_obj); 165 if (!other.isValid()) { 166 return thread->raiseWithFmt(LayoutId::kTypeError, "can't concat %T to %T", 167 &other_obj, &self); 168 } 169 170 word num_items = self.numItems(); 171 word other_length = other.length(); 172 word new_length = num_items + other_length; 173 runtime->bytearrayEnsureCapacity(thread, self, new_length); 174 MutableBytes::cast(self.items()) 175 .replaceFromWithByteslike(num_items, other, other_length); 176 self.setNumItems(new_length); 177 return *self; 178} 179 180RawObject METH(bytearray, __imul__)(Thread* thread, Arguments args) { 181 Runtime* runtime = thread->runtime(); 182 HandleScope scope(thread); 183 Object self_obj(&scope, args.get(0)); 184 if (!runtime->isInstanceOfBytearray(*self_obj)) { 185 return thread->raiseRequiresType(self_obj, ID(bytearray)); 186 } 187 Bytearray self(&scope, *self_obj); 188 Object count_index(&scope, args.get(1)); 189 Object count_obj(&scope, intFromIndex(thread, count_index)); 190 if (count_obj.isError()) return *count_obj; 191 word count = intUnderlying(*count_obj).asWordSaturated(); 192 if (!SmallInt::isValid(count)) { 193 return thread->raiseWithFmt(LayoutId::kOverflowError, 194 "cannot fit '%T' into an index-sized integer", 195 &count_index); 196 } 197 if (count == 1) { 198 return *self; 199 } 200 word length = self.numItems(); 201 if (count <= 0 || length == 0) { 202 self.downsize(0); 203 return *self; 204 } 205 word new_length; 206 if (__builtin_mul_overflow(length, count, &new_length) || 207 !SmallInt::isValid(new_length)) { 208 return thread->raiseMemoryError(); 209 } 210 Bytes source(&scope, self.items()); 211 if (new_length <= self.capacity()) { 212 // fits into existing backing LargeBytes - repeat in place 213 for (word i = 1; i < count; i++) { 214 runtime->bytearrayIadd(thread, self, source, length); 215 } 216 return *self; 217 } 218 // grows beyond existing bytes - allocate new 219 self.setItems(runtime->bytesRepeat(thread, source, length, count)); 220 DCHECK(self.capacity() == new_length, "unexpected result length"); 221 self.setNumItems(new_length); 222 return *self; 223} 224 225RawObject METH(bytearray, __iter__)(Thread* thread, Arguments args) { 226 HandleScope scope(thread); 227 Object self_obj(&scope, args.get(0)); 228 Runtime* runtime = thread->runtime(); 229 if (!runtime->isInstanceOfBytearray(*self_obj)) { 230 return thread->raiseRequiresType(self_obj, ID(bytearray)); 231 } 232 Bytearray self(&scope, *self_obj); 233 return runtime->newBytearrayIterator(thread, self); 234} 235 236RawObject METH(bytearray, __le__)(Thread* thread, Arguments args) { 237 Runtime* runtime = thread->runtime(); 238 HandleScope scope(thread); 239 Object self_obj(&scope, args.get(0)); 240 if (!runtime->isInstanceOfBytearray(*self_obj)) { 241 return thread->raiseRequiresType(self_obj, ID(bytearray)); 242 } 243 Bytearray self(&scope, *self_obj); 244 Object other_obj(&scope, args.get(1)); 245 word comparison; 246 if (runtime->isInstanceOfBytes(*other_obj)) { 247 Bytes other(&scope, bytesUnderlying(*other_obj)); 248 comparison = self.compare(*other, other.length()); 249 } else if (runtime->isInstanceOfBytearray(*other_obj)) { 250 Bytearray other(&scope, *other_obj); 251 Bytes other_bytes(&scope, other.items()); 252 comparison = self.compare(*other_bytes, other.numItems()); 253 } else { 254 // TODO(T38246066): allow any bytes-like object 255 return NotImplementedType::object(); 256 } 257 return Bool::fromBool(comparison <= 0); 258} 259 260RawObject METH(bytearray, __len__)(Thread* thread, Arguments args) { 261 HandleScope scope(thread); 262 Object self_obj(&scope, args.get(0)); 263 if (!thread->runtime()->isInstanceOfBytearray(*self_obj)) { 264 return thread->raiseRequiresType(self_obj, ID(bytearray)); 265 } 266 Bytearray self(&scope, *self_obj); 267 return SmallInt::fromWord(self.numItems()); 268} 269 270RawObject METH(bytearray, __lt__)(Thread* thread, Arguments args) { 271 Runtime* runtime = thread->runtime(); 272 HandleScope scope(thread); 273 Object self_obj(&scope, args.get(0)); 274 if (!runtime->isInstanceOfBytearray(*self_obj)) { 275 return thread->raiseRequiresType(self_obj, ID(bytearray)); 276 } 277 Bytearray self(&scope, *self_obj); 278 Object other_obj(&scope, args.get(1)); 279 word comparison; 280 if (runtime->isInstanceOfBytes(*other_obj)) { 281 Bytes other(&scope, bytesUnderlying(*other_obj)); 282 comparison = self.compare(*other, other.length()); 283 } else if (runtime->isInstanceOfBytearray(*other_obj)) { 284 Bytearray other(&scope, *other_obj); 285 Bytes other_bytes(&scope, other.items()); 286 comparison = self.compare(*other_bytes, other.numItems()); 287 } else { 288 // TODO(T38246066): allow any bytes-like object 289 return NotImplementedType::object(); 290 } 291 return Bool::fromBool(comparison < 0); 292} 293 294RawObject METH(bytearray, __mul__)(Thread* thread, Arguments args) { 295 Runtime* runtime = thread->runtime(); 296 HandleScope scope(thread); 297 Object self_obj(&scope, args.get(0)); 298 if (!runtime->isInstanceOfBytearray(*self_obj)) { 299 return thread->raiseRequiresType(self_obj, ID(bytearray)); 300 } 301 Bytearray self(&scope, *self_obj); 302 Object count_index(&scope, args.get(1)); 303 Object count_obj(&scope, intFromIndex(thread, count_index)); 304 if (count_obj.isError()) return *count_obj; 305 word count = intUnderlying(*count_obj).asWordSaturated(); 306 if (!SmallInt::isValid(count)) { 307 return thread->raiseWithFmt(LayoutId::kOverflowError, 308 "cannot fit '%T' into an index-sized integer", 309 &count_index); 310 } 311 word length = self.numItems(); 312 if (count <= 0 || length == 0) { 313 return runtime->newBytearray(); 314 } 315 word new_length; 316 if (__builtin_mul_overflow(length, count, &new_length) || 317 !SmallInt::isValid(new_length)) { 318 return thread->raiseMemoryError(); 319 } 320 Bytes source(&scope, self.items()); 321 Bytearray result(&scope, runtime->newBytearray()); 322 Bytes repeated(&scope, runtime->bytesRepeat(thread, source, length, count)); 323 DCHECK(repeated.length() == new_length, "unexpected result length"); 324 if (repeated.isSmallBytes()) { 325 runtime->bytearrayIadd(thread, result, repeated, new_length); 326 } else { 327 result.setItems(*repeated); 328 result.setNumItems(new_length); 329 } 330 return *result; 331} 332 333RawObject METH(bytearray, __ne__)(Thread* thread, Arguments args) { 334 Runtime* runtime = thread->runtime(); 335 HandleScope scope(thread); 336 Object self_obj(&scope, args.get(0)); 337 if (!runtime->isInstanceOfBytearray(*self_obj)) { 338 return thread->raiseRequiresType(self_obj, ID(bytearray)); 339 } 340 Bytearray self(&scope, *self_obj); 341 Object other_obj(&scope, args.get(1)); 342 word comparison; 343 if (runtime->isInstanceOfBytes(*other_obj)) { 344 Bytes other(&scope, bytesUnderlying(*other_obj)); 345 comparison = self.compare(*other, other.length()); 346 } else if (runtime->isInstanceOfBytearray(*other_obj)) { 347 Bytearray other(&scope, *other_obj); 348 Bytes other_bytes(&scope, other.items()); 349 comparison = self.compare(*other_bytes, other.numItems()); 350 } else { 351 // TODO(T38246066): allow any bytes-like object 352 return NotImplementedType::object(); 353 } 354 return Bool::fromBool(comparison != 0); 355} 356 357RawObject METH(bytearray, __new__)(Thread* thread, Arguments args) { 358 HandleScope scope(thread); 359 Object type_obj(&scope, args.get(0)); 360 Runtime* runtime = thread->runtime(); 361 if (!runtime->isInstanceOfType(*type_obj)) { 362 return thread->raiseWithFmt(LayoutId::kTypeError, "not a type object"); 363 } 364 Type type(&scope, *type_obj); 365 if (type.builtinBase() != LayoutId::kBytearray) { 366 return thread->raiseWithFmt(LayoutId::kTypeError, 367 "not a subtype of bytearray"); 368 } 369 Layout layout(&scope, type.instanceLayout()); 370 Bytearray result(&scope, runtime->newInstance(layout)); 371 result.setItems(runtime->emptyMutableBytes()); 372 result.setNumItems(0); 373 return *result; 374} 375 376RawObject bytearrayRepr(Thread* thread, const Bytearray& array) { 377 HandleScope scope(thread); 378 Runtime* runtime = thread->runtime(); 379 Type cls(&scope, runtime->typeOf(*array)); 380 Str name(&scope, cls.name()); 381 word name_length = name.length(); 382 word length = array.numItems(); 383 if (length > (kMaxWord - 6 - name_length) / 4) { 384 return thread->raiseWithFmt(LayoutId::kOverflowError, 385 "bytearray object is too large to make repr"); 386 } 387 388 // Precalculate length and determine which quote to use; single is preferred 389 word result_length = name_length + length + 5; // <cls>(b'<contents>') 390 bool has_single_quote = false; 391 bool has_double_quote = false; 392 for (word i = 0; i < length; i++) { 393 byte current = array.byteAt(i); 394 switch (current) { 395 case '\'': 396 result_length++; 397 has_single_quote = true; 398 break; 399 case '"': 400 has_double_quote = true; 401 break; 402 case '\t': 403 case '\n': 404 case '\r': 405 case '\\': 406 result_length++; 407 break; 408 default: 409 if (!ASCII::isPrintable(current)) { 410 result_length += 3; 411 } 412 } 413 } 414 byte delimiter = (has_single_quote && !has_double_quote) ? '"' : '\''; 415 416 MutableBytes result(&scope, 417 runtime->newMutableBytesUninitialized(result_length)); 418 word j = 0; 419 result.replaceFromWithStr(0, *name, name_length); 420 j += name_length; 421 result.byteAtPut(j++, '('); 422 result.byteAtPut(j++, 'b'); 423 result.byteAtPut(j++, delimiter); 424 425 for (word i = 0; i < length; i++) { 426 byte current = array.byteAt(i); 427 switch (current) { 428 case '\'': 429 result.byteAtPut(j++, '\\'); 430 result.byteAtPut(j++, current); 431 break; 432 case '\t': 433 result.byteAtPut(j++, '\\'); 434 result.byteAtPut(j++, 't'); 435 break; 436 case '\n': 437 result.byteAtPut(j++, '\\'); 438 result.byteAtPut(j++, 'n'); 439 break; 440 case '\r': 441 result.byteAtPut(j++, '\\'); 442 result.byteAtPut(j++, 'r'); 443 break; 444 case '\\': 445 result.byteAtPut(j++, '\\'); 446 result.byteAtPut(j++, '\\'); 447 break; 448 default: 449 if (ASCII::isPrintable(current)) { 450 result.byteAtPut(j++, current); 451 } else { 452 result.byteAtPut(j++, '\\'); 453 result.byteAtPut(j++, 'x'); 454 uwordToHexadecimalWithMutableBytes(*result, /*index=*/j, 455 /*num_digits=*/2, current); 456 j += 2; 457 } 458 } 459 } 460 461 result.byteAtPut(j++, delimiter); 462 result.byteAtPut(j++, ')'); 463 DCHECK(j == result_length, "expected %ld bytes, wrote %ld", result_length, j); 464 return result.becomeStr(); 465} 466 467RawObject METH(bytearray, __repr__)(Thread* thread, Arguments args) { 468 HandleScope scope(thread); 469 Object self_obj(&scope, args.get(0)); 470 Runtime* runtime = thread->runtime(); 471 if (!runtime->isInstanceOfBytearray(*self_obj)) { 472 return thread->raiseRequiresType(self_obj, ID(bytearray)); 473 } 474 Bytearray self(&scope, *self_obj); 475 return bytearrayRepr(thread, self); 476} 477 478RawObject METH(bytearray, hex)(Thread* thread, Arguments args) { 479 HandleScope scope(thread); 480 Object obj(&scope, args.get(0)); 481 if (!thread->runtime()->isInstanceOfBytearray(*obj)) { 482 return thread->raiseRequiresType(obj, ID(bytearray)); 483 } 484 Bytearray self(&scope, *obj); 485 Bytes bytes(&scope, self.items()); 486 return bytesHex(thread, bytes, self.numItems()); 487} 488 489RawObject METH(bytearray, lower)(Thread* thread, Arguments args) { 490 HandleScope scope(thread); 491 Object self_obj(&scope, args.get(0)); 492 Runtime* runtime = thread->runtime(); 493 if (!runtime->isInstanceOfBytearray(*self_obj)) { 494 return thread->raiseRequiresType(self_obj, ID(bytearray)); 495 } 496 Bytearray self(&scope, *self_obj); 497 Bytes items(&scope, self.items()); 498 word num_items = self.numItems(); 499 MutableBytes lowered(&scope, 500 runtime->newMutableBytesUninitialized(items.length())); 501 for (word i = 0; i < num_items; i++) { 502 lowered.byteAtPut(i, ASCII::toLower(items.byteAt(i))); 503 } 504 Bytearray result(&scope, runtime->newBytearray()); 505 result.setItems(*lowered); 506 result.setNumItems(num_items); 507 return *result; 508} 509 510RawObject METH(bytearray, lstrip)(Thread* thread, Arguments args) { 511 HandleScope scope(thread); 512 Object self_obj(&scope, args.get(0)); 513 Runtime* runtime = thread->runtime(); 514 if (!runtime->isInstanceOfBytearray(*self_obj)) { 515 return thread->raiseRequiresType(self_obj, ID(bytearray)); 516 } 517 Bytearray self(&scope, *self_obj); 518 Bytes self_bytes(&scope, self.items()); 519 Object chars_obj(&scope, args.get(1)); 520 Bytes result_bytes(&scope, Bytes::empty()); 521 if (chars_obj.isNoneType()) { 522 result_bytes = bytesStripSpaceLeft(thread, self_bytes, self.numItems()); 523 } else if (runtime->isInstanceOfBytes(*chars_obj)) { 524 Bytes chars(&scope, bytesUnderlying(*chars_obj)); 525 result_bytes = bytesStripLeft(thread, self_bytes, self.numItems(), chars, 526 chars.length()); 527 } else if (runtime->isInstanceOfBytearray(*chars_obj)) { 528 Bytearray chars(&scope, *chars_obj); 529 Bytes chars_bytes(&scope, chars.items()); 530 result_bytes = bytesStripLeft(thread, self_bytes, self.numItems(), 531 chars_bytes, chars.numItems()); 532 } else { 533 // TODO(T38246066): support bytes-like objects other than bytes, bytearray 534 return thread->raiseWithFmt(LayoutId::kTypeError, 535 "a bytes-like object is required, not '%T'", 536 &chars_obj); 537 } 538 Bytearray result(&scope, runtime->newBytearray()); 539 runtime->bytearrayIadd(thread, result, result_bytes, result_bytes.length()); 540 return *result; 541} 542 543RawObject METH(bytearray, rstrip)(Thread* thread, Arguments args) { 544 HandleScope scope(thread); 545 Object self_obj(&scope, args.get(0)); 546 Runtime* runtime = thread->runtime(); 547 if (!runtime->isInstanceOfBytearray(*self_obj)) { 548 return thread->raiseRequiresType(self_obj, ID(bytearray)); 549 } 550 Bytearray self(&scope, *self_obj); 551 Bytes self_bytes(&scope, self.items()); 552 Object chars_obj(&scope, args.get(1)); 553 Bytes result_bytes(&scope, Bytes::empty()); 554 if (chars_obj.isNoneType()) { 555 result_bytes = bytesStripSpaceRight(thread, self_bytes, self.numItems()); 556 } else if (runtime->isInstanceOfBytes(*chars_obj)) { 557 Bytes chars(&scope, bytesUnderlying(*chars_obj)); 558 result_bytes = bytesStripRight(thread, self_bytes, self.numItems(), chars, 559 chars.length()); 560 } else if (runtime->isInstanceOfBytearray(*chars_obj)) { 561 Bytearray chars(&scope, *chars_obj); 562 Bytes chars_bytes(&scope, chars.items()); 563 result_bytes = bytesStripRight(thread, self_bytes, self.numItems(), 564 chars_bytes, chars.numItems()); 565 } else { 566 // TODO(T38246066): support bytes-like objects other than bytes, bytearray 567 return thread->raiseWithFmt(LayoutId::kTypeError, 568 "a bytes-like object is required, not '%T'", 569 &chars_obj); 570 } 571 Bytearray result(&scope, runtime->newBytearray()); 572 runtime->bytearrayIadd(thread, result, result_bytes, result_bytes.length()); 573 return *result; 574} 575 576RawObject METH(bytearray, strip)(Thread* thread, Arguments args) { 577 HandleScope scope(thread); 578 Object self_obj(&scope, args.get(0)); 579 Runtime* runtime = thread->runtime(); 580 if (!runtime->isInstanceOfBytearray(*self_obj)) { 581 return thread->raiseRequiresType(self_obj, ID(bytearray)); 582 } 583 Bytearray self(&scope, *self_obj); 584 Bytes self_bytes(&scope, self.items()); 585 Object chars_obj(&scope, args.get(1)); 586 Bytes result_bytes(&scope, Bytes::empty()); 587 if (chars_obj.isNoneType()) { 588 result_bytes = bytesStripSpace(thread, self_bytes, self.numItems()); 589 } else if (runtime->isInstanceOfBytes(*chars_obj)) { 590 Bytes chars(&scope, bytesUnderlying(*chars_obj)); 591 result_bytes = 592 bytesStrip(thread, self_bytes, self.numItems(), chars, chars.length()); 593 } else if (runtime->isInstanceOfBytearray(*chars_obj)) { 594 Bytearray chars(&scope, *chars_obj); 595 Bytes chars_bytes(&scope, chars.items()); 596 result_bytes = bytesStrip(thread, self_bytes, self.numItems(), chars_bytes, 597 chars.numItems()); 598 } else { 599 // TODO(T38246066): support bytes-like objects other than bytes, bytearray 600 return thread->raiseWithFmt(LayoutId::kTypeError, 601 "a bytes-like object is required, not '%T'", 602 &chars_obj); 603 } 604 Bytearray result(&scope, runtime->newBytearray()); 605 runtime->bytearrayIadd(thread, result, result_bytes, result_bytes.length()); 606 return *result; 607} 608 609RawObject METH(bytearray, translate)(Thread* thread, Arguments args) { 610 HandleScope scope(thread); 611 Object self_obj(&scope, args.get(0)); 612 Runtime* runtime = thread->runtime(); 613 if (!runtime->isInstanceOfBytearray(*self_obj)) { 614 return thread->raiseRequiresType(self_obj, ID(bytearray)); 615 } 616 Bytearray self(&scope, *self_obj); 617 Bytes self_bytes(&scope, self.items()); 618 Object table_obj(&scope, args.get(1)); 619 word table_length; 620 if (table_obj.isNoneType()) { 621 table_length = kByteTranslationTableLength; 622 table_obj = Bytes::empty(); 623 } else if (runtime->isInstanceOfBytes(*table_obj)) { 624 Bytes bytes(&scope, bytesUnderlying(*table_obj)); 625 table_length = bytes.length(); 626 table_obj = *bytes; 627 } else if (runtime->isInstanceOfBytearray(*table_obj)) { 628 Bytearray array(&scope, *table_obj); 629 table_length = array.numItems(); 630 table_obj = array.items(); 631 } else { 632 // TODO(T38246066): allow any bytes-like object 633 return thread->raiseWithFmt(LayoutId::kTypeError, 634 "a bytes-like object is required, not '%T'", 635 &table_obj); 636 } 637 if (table_length != kByteTranslationTableLength) { 638 return thread->raiseWithFmt(LayoutId::kValueError, 639 "translation table must be %w characters long", 640 kByteTranslationTableLength); 641 } 642 Bytes table(&scope, *table_obj); 643 Object del(&scope, args.get(2)); 644 Bytes translated(&scope, Bytes::empty()); 645 if (runtime->isInstanceOfBytes(*del)) { 646 Bytes bytes(&scope, bytesUnderlying(*del)); 647 translated = 648 runtime->bytesTranslate(thread, self_bytes, self.numItems(), table, 649 table_length, bytes, bytes.length()); 650 } else if (runtime->isInstanceOfBytearray(*del)) { 651 Bytearray array(&scope, *del); 652 Bytes bytes(&scope, array.items()); 653 translated = 654 runtime->bytesTranslate(thread, self_bytes, self.numItems(), table, 655 table_length, bytes, array.numItems()); 656 } else { 657 // TODO(T38246066): allow any bytes-like object 658 return thread->raiseWithFmt(LayoutId::kTypeError, 659 "a bytes-like object is required, not '%T'", 660 &del); 661 } 662 Bytearray result(&scope, runtime->newBytearray()); 663 if (translated.isSmallBytes()) { 664 runtime->bytearrayIadd(thread, result, translated, translated.length()); 665 } else { 666 result.setItems(*translated); 667 result.setNumItems(translated.length()); 668 } 669 return *result; 670} 671 672RawObject METH(bytearray, upper)(Thread* thread, Arguments args) { 673 HandleScope scope(thread); 674 Object self_obj(&scope, args.get(0)); 675 Runtime* runtime = thread->runtime(); 676 if (!runtime->isInstanceOfBytearray(*self_obj)) { 677 return thread->raiseRequiresType(self_obj, ID(bytearray)); 678 } 679 Bytearray self(&scope, *self_obj); 680 Bytes items(&scope, self.items()); 681 word num_items = self.numItems(); 682 MutableBytes uppered(&scope, 683 runtime->newMutableBytesUninitialized(items.length())); 684 for (word i = 0; i < num_items; i++) { 685 uppered.byteAtPut(i, ASCII::toUpper(items.byteAt(i))); 686 } 687 Bytearray result(&scope, runtime->newBytearray()); 688 result.setItems(*uppered); 689 result.setNumItems(num_items); 690 return *result; 691} 692 693static RawObject bytearraySplitLines(Thread* thread, const Bytearray& bytearray, 694 bool keepends) { 695 HandleScope scope(thread); 696 Runtime* runtime = thread->runtime(); 697 List result(&scope, runtime->newList()); 698 word length = bytearray.numItems(); 699 Bytearray line(&scope, *bytearray); 700 701 for (word i = 0, j = 0; i < length; j = i) { 702 // Skip newline bytes 703 for (; i < length; i++) { 704 byte b = bytearray.byteAt(i); 705 if (b == '\n' || b == '\r') { 706 break; 707 } 708 } 709 710 word eol_pos = i; 711 if (i < length) { 712 word cur = i; 713 word next = i + 1; 714 i++; 715 // Check for \r\n specifically 716 if (bytearray.byteAt(cur) == '\r' && next < length && 717 bytearray.byteAt(next) == '\n') { 718 i++; 719 } 720 if (keepends) { 721 eol_pos = i; 722 } 723 } 724 725 line = runtime->newBytearray(); 726 word line_length = eol_pos - j; 727 runtime->bytearrayEnsureCapacity(thread, line, line_length); 728 line.setNumItems(line_length); 729 line.replaceFromWithStartAt(0, *bytearray, line_length, j); 730 731 runtime->listAdd(thread, result, line); 732 } 733 734 return *result; 735} 736 737RawObject METH(bytearray, splitlines)(Thread* thread, Arguments args) { 738 HandleScope scope(thread); 739 Runtime* runtime = thread->runtime(); 740 Object self_obj(&scope, args.get(0)); 741 Object keepends_obj(&scope, args.get(1)); 742 if (!runtime->isInstanceOfBytearray(*self_obj)) { 743 return thread->raiseRequiresType(self_obj, ID(bytearray)); 744 } 745 if (!runtime->isInstanceOfInt(*keepends_obj)) { 746 return thread->raiseRequiresType(keepends_obj, ID(int)); 747 } 748 Bytearray self(&scope, *self_obj); 749 bool keepends = !intUnderlying(*keepends_obj).isZero(); 750 return bytearraySplitLines(thread, self, keepends); 751} 752 753RawObject METH(bytearray_iterator, __iter__)(Thread* thread, Arguments args) { 754 HandleScope scope(thread); 755 Object self(&scope, args.get(0)); 756 if (!self.isBytearrayIterator()) { 757 return thread->raiseRequiresType(self, ID(bytearray_iterator)); 758 } 759 return *self; 760} 761 762RawObject METH(bytearray_iterator, __next__)(Thread* thread, Arguments args) { 763 HandleScope scope(thread); 764 Object self_obj(&scope, args.get(0)); 765 if (!self_obj.isBytearrayIterator()) { 766 return thread->raiseRequiresType(self_obj, ID(bytearray_iterator)); 767 } 768 BytearrayIterator self(&scope, *self_obj); 769 Bytearray bytearray(&scope, self.iterable()); 770 if (self.index() >= bytearray.numItems()) { 771 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 772 } 773 Int item(&scope, thread->runtime()->newInt(bytearray.byteAt(self.index()))); 774 self.setIndex(self.index() + 1); 775 return *item; 776} 777 778RawObject METH(bytearray_iterator, __length_hint__)(Thread* thread, 779 Arguments args) { 780 HandleScope scope(thread); 781 Object self_obj(&scope, args.get(0)); 782 if (!self_obj.isBytearrayIterator()) { 783 return thread->raiseRequiresType(self_obj, ID(bytearray_iterator)); 784 } 785 BytearrayIterator self(&scope, *self_obj); 786 Bytearray bytearray(&scope, self.iterable()); 787 return SmallInt::fromWord(bytearray.numItems() - self.index()); 788} 789 790} // namespace py