this repo has no description
at trunk 674 lines 24 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "memoryview-builtins.h" 3 4#include "builtins.h" 5#include "bytes-builtins.h" 6#include "float-builtins.h" 7#include "int-builtins.h" 8#include "mmap-module.h" 9#include "type-builtins.h" 10 11namespace py { 12 13static const BuiltinAttribute kMemoryViewAttributes[] = { 14 {ID(_memoryview__buffer), RawMemoryView::kBufferOffset, 15 AttributeFlags::kHidden}, 16 {ID(format), RawMemoryView::kFormatOffset, AttributeFlags::kReadOnly}, 17 {ID(_memoryview__length), RawMemoryView::kLengthOffset, 18 AttributeFlags::kHidden}, 19 {ID(readonly), RawMemoryView::kReadOnlyOffset, AttributeFlags::kReadOnly}, 20 {ID(obj), RawMemoryView::kObjectOffset, AttributeFlags::kReadOnly}, 21 {ID(shape), RawMemoryView::kShapeOffset, AttributeFlags::kReadOnly}, 22 {ID(_memoryview__start), RawMemoryView::kStartOffset, 23 AttributeFlags::kHidden}, 24 {ID(strides), RawMemoryView::kStridesOffset, AttributeFlags::kReadOnly}, 25 {ID(ndim), RawMemoryView::kNdimOffset, AttributeFlags::kReadOnly}, 26}; 27 28void initializeMemoryViewType(Thread* thread) { 29 addBuiltinType(thread, ID(memoryview), LayoutId::kMemoryView, 30 /*superclass_id=*/LayoutId::kObject, kMemoryViewAttributes, 31 MemoryView::kSize, /*basetype=*/false); 32} 33 34static char formatChar(const Str& format) { 35 if (format.length() == 2) { 36 if (format.byteAt(0) != '@') return -1; 37 return format.byteAt(1); 38 } 39 if (format.length() != 1) return -1; 40 return format.byteAt(0); 41} 42 43static word itemSize(char format) { 44 switch (format) { 45 case 'c': 46 case 'b': 47 case 'B': 48 return kByteSize; 49 case 'h': 50 case 'H': 51 return kShortSize; 52 case 'i': 53 case 'I': 54 return kIntSize; 55 case 'l': 56 case 'L': 57 return kLongSize; 58 case 'q': 59 case 'Q': 60 return kLongLongSize; 61 case 'n': 62 case 'N': 63 return kWordSize; 64 case 'f': 65 return kFloatSize; 66 case 'd': 67 return kDoubleSize; 68 case '?': 69 return kBoolSize; 70 case 'P': 71 return kPointerSize; 72 default: 73 return -1; 74 } 75} 76 77word memoryviewItemsize(Thread* thread, const MemoryView& view) { 78 HandleScope scope(thread); 79 Str format(&scope, view.format()); 80 char format_c = formatChar(format); 81 DCHECK(format_c > 0, "invalid memoryview"); 82 word item_size = itemSize(format_c); 83 DCHECK(item_size > 0, "invalid memoryview"); 84 return item_size; 85} 86 87static RawObject raiseInvalidValueError(Thread* thread, char format) { 88 return thread->raiseWithFmt(LayoutId::kValueError, 89 "memoryview: invalid value for format '%c'", 90 format); 91} 92 93static RawObject raiseInvalidTypeError(Thread* thread, char format) { 94 return thread->raiseWithFmt( 95 LayoutId::kTypeError, "memoryview: invalid type for format '%c'", format); 96} 97 98static bool isIntFormat(char format) { 99 switch (format) { 100 case 'b': 101 FALLTHROUGH; 102 case 'h': 103 FALLTHROUGH; 104 case 'i': 105 FALLTHROUGH; 106 case 'l': 107 FALLTHROUGH; 108 case 'B': 109 FALLTHROUGH; 110 case 'H': 111 FALLTHROUGH; 112 case 'I': 113 FALLTHROUGH; 114 case 'L': 115 FALLTHROUGH; 116 case 'q': 117 FALLTHROUGH; 118 case 'Q': 119 FALLTHROUGH; 120 case 'n': 121 FALLTHROUGH; 122 case 'N': 123 FALLTHROUGH; 124 case 'P': 125 return true; 126 default: 127 return false; 128 } 129} 130 131static RawObject packObject(Thread* thread, uword address, char format, 132 word index, RawObject value) { 133 byte* dst = reinterpret_cast<byte*>(address + index); 134 if (isIntFormat(format)) { 135 if (!value.isInt()) return Unbound::object(); 136 switch (format) { 137 case 'b': { 138 OptInt<char> opt_val = RawInt::cast(value).asInt<char>(); 139 if (opt_val.error != CastError::None) { 140 return raiseInvalidValueError(thread, format); 141 } 142 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 143 break; 144 } 145 case 'h': { 146 OptInt<short> opt_val = RawInt::cast(value).asInt<short>(); 147 if (opt_val.error != CastError::None) { 148 return raiseInvalidValueError(thread, format); 149 } 150 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 151 break; 152 } 153 case 'i': { 154 OptInt<int> opt_val = RawInt::cast(value).asInt<int>(); 155 if (opt_val.error != CastError::None) { 156 return raiseInvalidValueError(thread, format); 157 } 158 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 159 break; 160 } 161 case 'l': { 162 OptInt<long> opt_val = RawInt::cast(value).asInt<long>(); 163 if (opt_val.error != CastError::None) { 164 return raiseInvalidValueError(thread, format); 165 } 166 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 167 break; 168 } 169 case 'B': { 170 OptInt<unsigned char> opt_val = 171 RawInt::cast(value).asInt<unsigned char>(); 172 if (opt_val.error != CastError::None) { 173 return raiseInvalidValueError(thread, format); 174 } 175 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 176 break; 177 } 178 case 'H': { 179 OptInt<unsigned short> opt_val = 180 RawInt::cast(value).asInt<unsigned short>(); 181 if (opt_val.error != CastError::None) { 182 return raiseInvalidValueError(thread, format); 183 } 184 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 185 break; 186 } 187 case 'I': { 188 OptInt<unsigned int> opt_val = 189 RawInt::cast(value).asInt<unsigned int>(); 190 if (opt_val.error != CastError::None) { 191 return raiseInvalidValueError(thread, format); 192 } 193 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 194 break; 195 } 196 case 'L': { 197 OptInt<unsigned long> opt_val = 198 RawInt::cast(value).asInt<unsigned long>(); 199 if (opt_val.error != CastError::None) { 200 return raiseInvalidValueError(thread, format); 201 } 202 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 203 break; 204 } 205 case 'q': { 206 OptInt<long long> opt_val = RawInt::cast(value).asInt<long long>(); 207 if (opt_val.error != CastError::None) { 208 return raiseInvalidValueError(thread, format); 209 } 210 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 211 break; 212 } 213 case 'Q': { 214 OptInt<unsigned long long> opt_val = 215 RawInt::cast(value).asInt<unsigned long long>(); 216 if (opt_val.error != CastError::None) { 217 return raiseInvalidValueError(thread, format); 218 } 219 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 220 break; 221 } 222 case 'n': { 223 OptInt<ssize_t> opt_val = RawInt::cast(value).asInt<ssize_t>(); 224 if (opt_val.error != CastError::None) { 225 return raiseInvalidValueError(thread, format); 226 } 227 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 228 break; 229 } 230 case 'N': { 231 OptInt<size_t> opt_val = RawInt::cast(value).asInt<size_t>(); 232 if (opt_val.error != CastError::None) { 233 return raiseInvalidValueError(thread, format); 234 } 235 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 236 break; 237 } 238 case 'P': { 239 OptInt<uintptr_t> opt_val = RawInt::cast(value).asInt<uintptr_t>(); 240 if (opt_val.error != CastError::None) { 241 return raiseInvalidValueError(thread, format); 242 } 243 std::memcpy(dst, &opt_val.value, sizeof(opt_val.value)); 244 break; 245 } 246 } 247 return NoneType::object(); 248 } 249 250 switch (format) { 251 case 'f': { 252 if (!value.isFloat()) return Unbound::object(); 253 float value_float = Float::cast(floatUnderlying(value)).value(); 254 std::memcpy(dst, &value_float, sizeof(value_float)); 255 return NoneType::object(); 256 } 257 258 case 'd': { 259 if (!value.isFloat()) return Unbound::object(); 260 double value_double = Float::cast(floatUnderlying(value)).value(); 261 std::memcpy(dst, &value_double, sizeof(value_double)); 262 return NoneType::object(); 263 } 264 265 case 'c': { 266 if (!value.isBytes()) return raiseInvalidTypeError(thread, format); 267 RawBytes value_bytes = bytesUnderlying(value); 268 if (value_bytes.length() != 1) { 269 return raiseInvalidValueError(thread, format); 270 } 271 *dst = value_bytes.byteAt(0); 272 return NoneType::object(); 273 } 274 275 case '?': { 276 if (!value.isBool()) return Unbound::object(); 277 bool value_bool = Bool::cast(value).value(); 278 std::memcpy(dst, &value_bool, sizeof(value_bool)); 279 return NoneType::object(); 280 } 281 default: 282 UNREACHABLE("invalid format"); 283 } 284 return NoneType::object(); 285} 286 287static RawObject unpackObject(Thread* thread, uword address, word length, 288 char format, word index) { 289 Runtime* runtime = thread->runtime(); 290 DCHECK_INDEX(index, length - static_cast<word>(itemSize(format) - 1)); 291 byte* src = reinterpret_cast<byte*>(address + index); 292 switch (format) { 293 case 'c': 294 return runtime->newBytes(1, Utils::readBytes<byte>(src)); 295 case 'b': 296 return RawSmallInt::fromWord(Utils::readBytes<signed char>(src)); 297 case 'B': 298 return RawSmallInt::fromWord(Utils::readBytes<unsigned char>(src)); 299 case 'h': 300 return RawSmallInt::fromWord(Utils::readBytes<short>(src)); 301 case 'H': 302 return RawSmallInt::fromWord(Utils::readBytes<unsigned short>(src)); 303 case 'i': 304 return runtime->newInt(Utils::readBytes<int>(src)); 305 case 'I': 306 return runtime->newInt(Utils::readBytes<unsigned int>(src)); 307 case 'l': 308 return runtime->newInt(Utils::readBytes<long>(src)); 309 case 'L': 310 return runtime->newIntFromUnsigned(Utils::readBytes<unsigned long>(src)); 311 case 'q': 312 return runtime->newInt(Utils::readBytes<long long>(src)); 313 case 'Q': 314 return runtime->newIntFromUnsigned( 315 Utils::readBytes<unsigned long long>(src)); 316 case 'n': 317 return runtime->newInt(Utils::readBytes<ssize_t>(src)); 318 case 'N': 319 return runtime->newIntFromUnsigned(Utils::readBytes<size_t>(src)); 320 case 'P': 321 return runtime->newIntFromCPtr(Utils::readBytes<void*>(src)); 322 case 'f': 323 return runtime->newFloat(Utils::readBytes<float>(src)); 324 case 'd': 325 return runtime->newFloat(Utils::readBytes<double>(src)); 326 case '?': { 327 return Bool::fromBool(Utils::readBytes<byte>(src) != 0); 328 } 329 default: 330 UNREACHABLE("invalid format"); 331 } 332} 333 334// Helper function that returns the location within the memoryview buffer to 335// find requested index 336static word bufferIndex(const MemoryView& view, word index) { 337 word step = intUnderlying(Tuple::cast(view.strides()).at(0)).asWord(); 338 if (step != 1) { 339 UNIMPLEMENTED("Stride != 1 is not yet supported"); 340 } 341 DCHECK_INDEX(index, view.length()); 342 return view.start() + index; 343} 344 345RawObject memoryviewGetitem(Thread* thread, const MemoryView& view, 346 word index) { 347 HandleScope scope(thread); 348 Object buffer(&scope, view.buffer()); 349 Runtime* runtime = thread->runtime(); 350 351 // TODO(T36619828) support str subclasses 352 Str format(&scope, view.format()); 353 char format_c = formatChar(format); 354 // TODO(T58046846): Replace DCHECK(char > 0) checks 355 DCHECK(format_c > 0, "invalid memoryview"); 356 word item_size = itemSize(format_c); 357 DCHECK(item_size > 0, "invalid memoryview"); 358 word buffer_index = bufferIndex(view, index); 359 360 if (runtime->isInstanceOfBytes(*buffer)) { 361 // TODO(T38246066) support bytes subclasses 362 if (buffer.isLargeBytes()) { 363 LargeBytes bytes(&scope, *buffer); 364 return unpackObject(thread, bytes.address(), bytes.length(), format_c, 365 buffer_index); 366 } 367 CHECK(buffer.isSmallBytes(), 368 "memoryview.__getitem__ with non bytes/memory"); 369 Bytes bytes(&scope, *buffer); 370 byte bytes_buffer[SmallBytes::kMaxLength]; 371 bytes.copyTo(bytes_buffer, bytes.length()); 372 return unpackObject(thread, reinterpret_cast<uword>(bytes_buffer), 373 bytes.length(), format_c, buffer_index); 374 } 375 CHECK(buffer.isPointer(), "memoryview.__getitem__ with non bytes/memory"); 376 void* cptr = Pointer::cast(*buffer).cptr(); 377 word ptr_length = Pointer::cast(*buffer).length(); 378 return unpackObject(thread, reinterpret_cast<uword>(cptr), ptr_length, 379 format_c, buffer_index); 380} 381 382RawObject memoryviewGetslice(Thread* thread, const MemoryView& view, word start, 383 word stop, word step) { 384 if (step != 1) { 385 UNIMPLEMENTED("Stride != 1 is not yet supported"); 386 } 387 388 HandleScope scope(thread); 389 Runtime* runtime = thread->runtime(); 390 391 Str format(&scope, view.format()); 392 char format_c = formatChar(format); 393 // TODO(T58046846): Replace DCHECK(char > 0) checks 394 DCHECK(format_c > 0, "invalid memoryview"); 395 word item_size = itemSize(format_c); 396 DCHECK(item_size > 0, "invalid memoryview"); 397 word slice_len = Slice::length(start, stop, step); 398 word slice_byte_size = slice_len * item_size; 399 400 Object buffer(&scope, view.buffer()); 401 Object obj(&scope, view.object()); 402 MemoryView result( 403 &scope, runtime->newMemoryView( 404 thread, obj, buffer, slice_byte_size, 405 view.readOnly() ? ReadOnly::ReadOnly : ReadOnly::ReadWrite)); 406 result.setFormat(view.format()); 407 result.setStart(view.start() + start * item_size); 408 return *result; 409} 410 411RawObject memoryviewSetitem(Thread* thread, const MemoryView& view, word index, 412 const Object& value) { 413 HandleScope scope(thread); 414 Object buffer(&scope, view.buffer()); 415 Str format(&scope, view.format()); 416 char fmt = formatChar(format); 417 // TODO(T58046846): Replace DCHECK(char > 0) checks 418 DCHECK(fmt > 0, "invalid memoryview"); 419 word item_size = itemSize(fmt); 420 DCHECK(item_size > 0, "invalid memoryview"); 421 422 word buffer_index = bufferIndex(view, index); 423 if (buffer.isMutableBytes()) { 424 return packObject(thread, LargeBytes::cast(*buffer).address(), fmt, 425 buffer_index, *value); 426 } 427 DCHECK(buffer.isPointer(), "memoryview.__setitem__ with non bytes/memory"); 428 void* cptr = Pointer::cast(*buffer).cptr(); 429 return packObject(thread, reinterpret_cast<uword>(cptr), fmt, buffer_index, 430 *value); 431} 432 433static RawObject raiseDifferentStructureError(Thread* thread) { 434 return thread->raiseWithFmt( 435 LayoutId::kValueError, 436 "memoryview assignment: lvalue and rvalue have different structures"); 437} 438 439RawObject memoryviewSetslice(Thread* thread, const MemoryView& view, word start, 440 word stop, word step, word slice_len, 441 const Object& value_obj) { 442 HandleScope scope(thread); 443 Runtime* runtime = thread->runtime(); 444 word stride = intUnderlying(Tuple::cast(view.strides()).at(0)).asWord(); 445 if (view.start() != 0 || stride != 1) { 446 UNIMPLEMENTED("Set item with slicing called on a sliced memoryview"); 447 } 448 449 Str format(&scope, view.format()); 450 char fmt = formatChar(format); 451 // TODO(T58046846): Replace DCHECK(char > 0) checks 452 DCHECK(fmt > 0, "invalid memoryview"); 453 Object buffer(&scope, view.buffer()); 454 Bytes value_bytes(&scope, Bytes::empty()); 455 if (runtime->isInstanceOfBytes(*value_obj)) { 456 value_bytes = *value_obj; 457 if (fmt != 'B' || value_bytes.length() != slice_len) { 458 return raiseDifferentStructureError(thread); 459 } 460 } else if (runtime->isInstanceOfBytearray(*value_obj)) { 461 Bytearray value_bytearray(&scope, *value_obj); 462 if (fmt != 'B' || value_bytearray.numItems() != slice_len) { 463 return raiseDifferentStructureError(thread); 464 } 465 value_bytes = value_bytearray.items(); 466 } else if (value_obj.isMemoryView()) { 467 MemoryView value(&scope, *value_obj); 468 Str value_format(&scope, value.format()); 469 char value_fmt = formatChar(value_format); 470 word item_size = itemSize(value_fmt); 471 DCHECK(item_size > 0, "invalid memoryview"); 472 if (fmt != value_fmt || (value.length() / item_size) != slice_len) { 473 return raiseDifferentStructureError(thread); 474 } 475 byte small_bytes_buf[SmallBytes::kMaxLength]; 476 uword value_address; 477 Object value_buffer(&scope, value.buffer()); 478 if (value_buffer.isLargeBytes()) { 479 value_address = LargeBytes::cast(*value_buffer).address(); 480 } else if (value_buffer.isInt()) { 481 value_address = Int::cast(*value_buffer).asInt<uword>().value; 482 } else { 483 DCHECK(value_buffer.isSmallBytes(), 484 "memoryview.__setitem__ with non bytes/memory"); 485 Bytes bytes(&scope, *value_buffer); 486 bytes.copyTo(small_bytes_buf, value.length()); 487 value_address = reinterpret_cast<uword>(small_bytes_buf); 488 } 489 uword address; 490 if (buffer.isMutableBytes()) { 491 address = LargeBytes::cast(*buffer).address(); 492 } else { 493 DCHECK(buffer.isPointer(), 494 "memoryview.__setitem__ with non bytes/memory"); 495 address = reinterpret_cast<uword>(Pointer::cast(*buffer).cptr()); 496 } 497 if (step == 1 && item_size == 1) { 498 std::memcpy(reinterpret_cast<void*>(address + start), 499 reinterpret_cast<void*>(value_address), slice_len); 500 } 501 start *= item_size; 502 step *= item_size; 503 for (; start < stop; value_address += item_size, start += step) { 504 std::memcpy(reinterpret_cast<void*>(address + start), 505 reinterpret_cast<void*>(value_address), item_size); 506 } 507 return NoneType::object(); 508 } else if (runtime->isByteslike(*value_obj)) { 509 UNIMPLEMENTED("unsupported bytes-like type"); 510 } else { 511 return thread->raiseWithFmt(LayoutId::kTypeError, 512 "a bytes-like object is required, not '%T'", 513 &value_obj); 514 } 515 byte* address; 516 if (buffer.isMutableBytes()) { 517 address = reinterpret_cast<byte*>(LargeBytes::cast(*buffer).address()); 518 } else { 519 DCHECK(buffer.isPointer(), "memoryview.__setitem__ with non bytes/memory"); 520 address = static_cast<byte*>(Pointer::cast(*buffer).cptr()); 521 } 522 if (step == 1) { 523 value_bytes.copyTo(address + start, slice_len); 524 return NoneType::object(); 525 } 526 for (word i = 0; start < stop; i++, start += step) { 527 address[start] = value_bytes.byteAt(i); 528 } 529 return NoneType::object(); 530} 531 532static word pow2_remainder(word dividend, word divisor) { 533 DCHECK(divisor > 0 && Utils::isPowerOfTwo(divisor), "must be power of two"); 534 word mask = divisor - 1; 535 return dividend & mask; 536} 537 538RawObject METH(memoryview, cast)(Thread* thread, Arguments args) { 539 HandleScope scope(thread); 540 Object self_obj(&scope, args.get(0)); 541 if (!self_obj.isMemoryView()) { 542 return thread->raiseRequiresType(self_obj, ID(memoryview)); 543 } 544 MemoryView self(&scope, *self_obj); 545 546 Runtime* runtime = thread->runtime(); 547 Object format_obj(&scope, args.get(1)); 548 if (!runtime->isInstanceOfStr(*format_obj)) { 549 return thread->raiseWithFmt(LayoutId::kTypeError, 550 "format argument must be a string"); 551 } 552 Str format(&scope, *format_obj); 553 char format_c = formatChar(format); 554 word item_size; 555 if (format_c < 0 || (item_size = itemSize(format_c)) < 0) { 556 return thread->raiseWithFmt( 557 LayoutId::kValueError, 558 "memoryview: destination must be a native single character format " 559 "prefixed with an optional '@'"); 560 } 561 562 word length = self.length(); 563 if (pow2_remainder(length, item_size) != 0) { 564 return thread->raiseWithFmt( 565 LayoutId::kValueError, 566 "memoryview: length is not a multiple of itemsize"); 567 } 568 Object buffer(&scope, self.buffer()); 569 Object obj(&scope, self.object()); 570 MemoryView result( 571 &scope, runtime->newMemoryView( 572 thread, obj, buffer, length, 573 self.readOnly() ? ReadOnly::ReadOnly : ReadOnly::ReadWrite)); 574 result.setFormat(*format); 575 return *result; 576} 577 578RawObject METH(memoryview, __len__)(Thread* thread, Arguments args) { 579 HandleScope scope(thread); 580 Object self_obj(&scope, args.get(0)); 581 if (!self_obj.isMemoryView()) { 582 return thread->raiseRequiresType(self_obj, ID(memoryview)); 583 } 584 MemoryView self(&scope, *self_obj); 585 // TODO(T36619828) support str subclasses 586 Str format(&scope, self.format()); 587 char format_c = formatChar(format); 588 DCHECK(format_c > 0, "invalid format"); 589 word item_size = itemSize(format_c); 590 DCHECK(item_size > 0, "invalid memoryview"); 591 return SmallInt::fromWord(self.length() / item_size); 592} 593 594RawObject METH(memoryview, __new__)(Thread* thread, Arguments args) { 595 HandleScope scope(thread); 596 Runtime* runtime = thread->runtime(); 597 if (args.get(0) != runtime->typeAt(LayoutId::kMemoryView)) { 598 return thread->raiseWithFmt(LayoutId::kTypeError, 599 "memoryview.__new__(X): X is not 'memoryview'"); 600 } 601 602 Object object(&scope, args.get(1)); 603 if (runtime->isInstanceOfBytes(*object)) { 604 Bytes bytes(&scope, bytesUnderlying(*object)); 605 MemoryView result( 606 &scope, runtime->newMemoryView(thread, object, bytes, bytes.length(), 607 ReadOnly::ReadOnly)); 608 return *result; 609 } 610 if (runtime->isInstanceOfBytearray(*object)) { 611 Bytearray bytearray(&scope, *object); 612 Bytes bytes(&scope, bytearray.items()); 613 MemoryView result(&scope, runtime->newMemoryView(thread, object, bytes, 614 bytearray.numItems(), 615 ReadOnly::ReadWrite)); 616 return *result; 617 } 618 if (object.isMemoryView()) { 619 MemoryView view(&scope, *object); 620 Object buffer(&scope, view.buffer()); 621 Object view_obj(&scope, view.object()); 622 MemoryView result( 623 &scope, runtime->newMemoryView(thread, view_obj, buffer, view.length(), 624 view.readOnly() ? ReadOnly::ReadOnly 625 : ReadOnly::ReadWrite)); 626 result.setFormat(view.format()); 627 return *result; 628 } 629 if (object.isMmap()) { 630 Mmap mmap_obj(&scope, *object); 631 Pointer pointer(&scope, mmap_obj.data()); 632 MemoryView result( 633 &scope, 634 runtime->newMemoryViewFromCPtr( 635 thread, object, pointer.cptr(), pointer.length(), 636 mmap_obj.isWritable() ? ReadOnly::ReadWrite : ReadOnly::ReadOnly)); 637 result.setFormat(SmallStr::fromCodePoint('B')); 638 return *result; 639 } 640 // Handle a buffer protocol object. Ideally we would skip an intermediate 641 // copy, but for now we make one copy of the data into a bytes. 642 // TODO(T85440357): Point directly to the buffer protocol object or 643 // bufferinfo from the memoryview. 644 Object bytes(&scope, newBytesFromBuffer(thread, object)); 645 if (bytes.isError()) { 646 return *bytes; 647 } 648 return runtime->newMemoryView( 649 thread, object, bytes, Bytes::cast(*bytes).length(), ReadOnly::ReadOnly); 650} 651 652RawObject METH(memoryview, tobytes)(Thread* thread, Arguments args) { 653 HandleScope scope(thread); 654 Object self_obj(&scope, args.get(0)); 655 if (!self_obj.isMemoryView()) { 656 return thread->raiseRequiresType(self_obj, ID(memoryview)); 657 } 658 MemoryView self(&scope, *self_obj); 659 word length = self.length(); 660 Runtime* runtime = thread->runtime(); 661 Object buffer(&scope, self.buffer()); 662 if (runtime->isInstanceOfBytes(*buffer)) { 663 MutableBytes result(&scope, runtime->newMutableBytesUninitialized(length)); 664 Bytes bytes(&scope, *buffer); 665 result.replaceFromWithBytes(0, *bytes, length); 666 return result.becomeImmutable(); 667 } 668 DCHECK(buffer.isPointer(), "memoryview.__getitem__ with non bytes/memory"); 669 void* cptr = Pointer::cast(*buffer).cptr(); 670 DCHECK(length <= Pointer::cast(*buffer).length(), "invalid length"); 671 return runtime->newBytesWithAll(View<byte>(static_cast<byte*>(cptr), length)); 672} 673 674} // namespace py