this repo has no description
at trunk 151 lines 6.0 kB view raw
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