this repo has no description
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