this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "structseq-builtins.h"
3
4#include "dict-builtins.h"
5#include "module-builtins.h"
6#include "runtime.h"
7#include "str-builtins.h"
8#include "type-builtins.h"
9
10namespace py {
11
12static const word kUserTupleFields = UserTupleBase::kSize / kPointerSize;
13
14RawObject structseqGetItem(Thread* thread, const Object& structseq,
15 word index) {
16 HandleScope scope(thread);
17 UserTupleBase user_tuple(&scope, *structseq);
18 Tuple tuple(&scope, user_tuple.value());
19 word num_in_sequence = tuple.length();
20 if (index < num_in_sequence) {
21 return tuple.at(index);
22 }
23 word attribute_index = index - num_in_sequence + kUserTupleFields;
24 CHECK_INDEX(attribute_index, user_tuple.headerCountOrOverflow());
25 return user_tuple.instanceVariableAt(attribute_index * kPointerSize);
26}
27
28RawObject structseqSetItem(Thread* thread, const Object& structseq, word index,
29 const Object& value) {
30 HandleScope scope(thread);
31 UserTupleBase user_tuple(&scope, *structseq);
32 Tuple tuple(&scope, user_tuple.value());
33 word num_in_sequence = tuple.length();
34 if (index < num_in_sequence) {
35 tuple.atPut(index, *value);
36 return NoneType::object();
37 }
38 word attribute_index = index - num_in_sequence + kUserTupleFields;
39 CHECK_INDEX(attribute_index, user_tuple.headerCountOrOverflow());
40 user_tuple.instanceVariableAtPut(attribute_index * kPointerSize, *value);
41 return NoneType::object();
42}
43
44RawObject structseqNew(Thread* thread, const Type& type) {
45 HandleScope scope(thread);
46 Runtime* runtime = thread->runtime();
47 Layout layout(&scope, type.instanceLayout());
48 UserTupleBase result(&scope, runtime->newInstance(layout));
49 Int n_sequence_fields(&scope,
50 typeAtById(thread, type, ID(n_sequence_fields)));
51 word num_fields = n_sequence_fields.asWord();
52 if (num_fields == 0) {
53 result.setValue(runtime->emptyTuple());
54 } else {
55 MutableTuple fields(&scope, runtime->newMutableTuple(num_fields));
56 fields.fill(NoneType::object());
57 result.setValue(fields.becomeImmutable());
58 }
59 return *result;
60}
61
62RawObject structseqNewType(Thread* thread, const Str& name,
63 const Tuple& field_names, word num_in_sequence,
64 word flags) {
65 HandleScope scope(thread);
66 Runtime* runtime = thread->runtime();
67 word num_fields = field_names.length();
68 DCHECK(num_in_sequence <= num_fields, "n_in_sequence too big");
69
70 Str type_name(&scope, *name);
71 Object module_name(&scope, NoneType::object());
72 word dot = strRFindAsciiChar(name, '.');
73 if (dot >= 0) {
74 module_name = strSubstr(thread, name, 0, dot);
75 type_name = strSubstr(thread, name, dot + 1, name.length() - (dot + 1));
76 } else {
77 module_name = runtime->symbols()->at(ID(builtins));
78 }
79
80 Dict dict(&scope, runtime->newDict());
81 dictAtPutById(thread, dict, ID(__qualname__), type_name);
82 dictAtPutById(thread, dict, ID(__module__), module_name);
83
84 // Create type
85 Object base(&scope, runtime->typeAt(LayoutId::kTuple));
86 Tuple bases(&scope, runtime->newTupleWith1(base));
87 Type metaclass(&scope, runtime->typeAt(LayoutId::kType));
88 Type type(&scope, typeNew(thread, metaclass, type_name, bases, dict, flags,
89 /*inherit_slots=*/true,
90 /*add_instance_dict=*/false));
91
92 // Add hidden fields as in-object attributes in the instance layout.
93 Layout layout(&scope, type.instanceLayout());
94 DCHECK(layout.numInObjectAttributes() == kUserTupleFields,
95 "unexpected number of attributes");
96 if (num_fields > num_in_sequence) {
97 Str field_name(&scope, Str::empty());
98 for (word i = num_in_sequence, offset = RawUserTupleBase::kSize;
99 i < num_fields; i++, offset += kPointerSize) {
100 AttributeInfo info(offset, AttributeFlags::kInObject);
101 Tuple entries(&scope, layout.inObjectAttributes());
102 field_name = field_names.at(i);
103 layout.setNumInObjectAttributes(layout.numInObjectAttributes() + 1);
104 layout.setInObjectAttributes(
105 runtime->layoutAddAttributeEntry(thread, entries, field_name, info));
106 }
107 }
108 layout.seal();
109
110 word num_unnamed_fields = 0;
111 Object field_name(&scope, Str::empty());
112 Object descriptor(&scope, NoneType::object());
113 SmallInt index(&scope, SmallInt::fromWord(0));
114 for (word i = 0; i < num_fields; i++) {
115 field_name = field_names.at(i);
116 if (field_name.isNoneType()) {
117 DCHECK(i < num_in_sequence, "unnamed fields must be in-sequence");
118 num_unnamed_fields++;
119 continue;
120 }
121 DCHECK(Runtime::isInternedStr(thread, field_name),
122 "field_names must contain interned strings or None");
123 index = SmallInt::fromWord(i);
124 descriptor = thread->invokeFunction2(ID(builtins), ID(_structseq_field),
125 type, index);
126 if (descriptor.isErrorException()) return *descriptor;
127 typeAtPut(thread, type, field_name, descriptor);
128 }
129
130 typeAtPutById(thread, type, ID(_structseq_field_names), field_names);
131 Object value(&scope, SmallInt::fromWord(num_fields));
132 typeAtPutById(thread, type, ID(n_fields), value);
133 value = SmallInt::fromWord(num_in_sequence);
134 typeAtPutById(thread, type, ID(n_sequence_fields), value);
135 value = SmallInt::fromWord(num_unnamed_fields);
136 typeAtPutById(thread, type, ID(n_unnamed_fields), value);
137
138 Module builtins(&scope, runtime->findModuleById(ID(builtins)));
139 value = moduleAtById(thread, builtins, ID(_structseq_new));
140 typeAtPutById(thread, type, ID(__new__), value);
141 CHECK(typeAtById(thread, type, ID(__new__)) == value, "");
142 Object n(&scope, runtime->symbols()->at(ID(__new__)));
143 CHECK(typeAt(type, n) == value, "");
144 CHECK(typeGetAttribute(thread, type, n) == value, "");
145 value = moduleAtById(thread, builtins, ID(_structseq_repr));
146 typeAtPutById(thread, type, ID(__repr__), value);
147
148 return *type;
149}
150
151} // namespace py