this repo has no description
at trunk 151 lines 5.0 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "byteslike.h" 3 4#include "array-module.h" 5#include "handles.h" 6#include "runtime.h" 7#include "unicode.h" 8 9namespace py { 10 11Byteslike::Byteslike(HandleScope* scope, Thread* thread, RawObject object) 12 : d_{} { 13 if (object.isSmallBytes()) { 14 RawSmallBytes small_bytes = SmallBytes::cast(object); 15 initWithSmallData(small_bytes, small_bytes.length()); 16 return; 17 } 18 if (object.isLargeBytes()) { 19 RawLargeBytes bytes = LargeBytes::cast(object); 20 initWithLargeBytes(scope, bytes, bytes.length()); 21 return; 22 } 23 if (object.isMemoryView()) { 24 RawMemoryView memory_view = MemoryView::cast(object); 25 RawObject buffer = memory_view.buffer(); 26 word length = memory_view.length(); 27 word start = memory_view.start(); 28 if (buffer.isLargeBytes()) { 29 if (start != 0) { 30 UNIMPLEMENTED("non-zero start on DataArray not supported yet"); 31 } 32 initWithLargeBytes(scope, LargeBytes::cast(buffer), length); 33 return; 34 } 35 if (buffer.isPointer()) { 36 byte* data = static_cast<byte*>(Pointer::cast(buffer).cptr()) + start; 37 initWithMemory(data, length); 38 return; 39 } 40 if (buffer.isSmallBytes()) { 41 initWithSmallData(SmallBytes::cast(buffer), length); 42 d_.small.reference += start; 43 return; 44 } 45 UNIMPLEMENTED("TODO memoryview from C extension object?"); 46 } 47 Runtime* runtime = thread->runtime(); 48 if (runtime->isInstanceOfBytearray(object)) { 49 RawBytearray bytearray = object.rawCast<RawBytearray>(); 50 initWithLargeBytes(scope, MutableBytes::cast(bytearray.items()), 51 bytearray.numItems()); 52 return; 53 } 54 if (runtime->isInstanceOfBytes(object)) { 55 RawObject bytes = object.rawCast<RawUserBytesBase>().value(); 56 if (bytes.isImmediateObjectNotSmallInt()) { 57 RawSmallBytes small_bytes = SmallBytes::cast(bytes); 58 initWithSmallData(small_bytes, small_bytes.length()); 59 return; 60 } 61 RawLargeBytes large_bytes = LargeBytes::cast(bytes); 62 initWithLargeBytes(scope, large_bytes, large_bytes.length()); 63 return; 64 } 65 if (runtime->isInstanceOfArray(object)) { 66 RawArray array = object.rawCast<RawArray>(); 67 word length = arrayByteLength(array); 68 initWithLargeBytes(scope, MutableBytes::cast(array.buffer()), length); 69 return; 70 } 71 DCHECK(!runtime->isByteslike(object), "expected non-byteslike"); 72 d_.handle.object = Error::error(); 73 next_ = nullptr; 74} 75 76inline void Byteslike::initWithLargeBytes(HandleScope* scope, 77 RawLargeBytes bytes, word length) { 78 static_assert(sizeof(Byteslike) == sizeof(Object) + sizeof(length_), 79 "size mismatch"); 80 81 DCHECK_BOUND(length, bytes.length()); 82 Thread* thread = scope->thread(); 83 d_.handle.object = bytes; 84 d_.handle.thread = thread; 85 Handle<RawObject>* as_handle = reinterpret_cast<Handle<RawObject>*>(this); 86 next_ = thread->handles()->push(as_handle); 87 length_ = length; 88} 89 90inline void Byteslike::initWithMemory(byte* data, word length) { 91 // Add `kHeapObjectTag` to the pointer. This mirrors the way references into 92 // the managed heap work (compare with `RawHeapObject::fromAddress`) so we can 93 // use the same code to access non-managed and managed memory. 94 d_.reference = reinterpret_cast<uword>(data) + Object::kHeapObjectTag; 95 next_ = nullptr; 96 length_ = length; 97} 98 99inline void Byteslike::initWithSmallData(RawSmallBytes bytes, word length) { 100 d_.small.small_storage = bytes; 101 const byte* data = smallDataData(&d_.small.small_storage); 102 // Add `kHeapObjectTag` to the pointer. This mirrors the way references into 103 // the managed heap work (compare with `RawHeapObject::fromAddress`) so we can 104 // use the same code to access non-managed and managed memory. 105 d_.small.reference = reinterpret_cast<uword>(data) + Object::kHeapObjectTag; 106 next_ = nullptr; 107 length_ = length; 108} 109 110RawObject byteslikeReprSmartQuotes(Thread* thread, const Byteslike& byteslike) { 111 // Precalculate the length of the result to minimize allocation. 112 word length = byteslike.length(); 113 word num_single_quotes = 0; 114 bool has_double_quotes = false; 115 word result_length = length + 3; // b'' 116 for (word i = 0; i < length; i++) { 117 byte current = byteslike.byteAt(i); 118 switch (current) { 119 case '\'': 120 num_single_quotes++; 121 break; 122 case '"': 123 has_double_quotes = true; 124 break; 125 case '\t': 126 case '\n': 127 case '\r': 128 case '\\': 129 result_length++; 130 break; 131 default: 132 if (!ASCII::isPrintable(current)) { 133 result_length += 3; 134 } 135 } 136 } 137 138 byte delimiter = '\''; 139 if (num_single_quotes > 0) { 140 if (has_double_quotes) { 141 result_length += num_single_quotes; 142 } else { 143 delimiter = '"'; 144 } 145 } 146 147 return thread->runtime()->byteslikeRepr(thread, byteslike, result_length, 148 delimiter); 149} 150 151} // namespace py