Merge branch 'master' into deploy-ng

This commit is contained in:
Mitchell Stokes 2017-12-02 18:36:47 -08:00
commit d90e59ca2d
66 changed files with 7365 additions and 5766 deletions

File diff suppressed because it is too large Load Diff

View File

@ -143,51 +143,52 @@ extern int cppyydebug;
KW_IS_TRIVIAL = 353,
KW_IS_UNION = 354,
KW_LONG = 355,
KW_MAKE_MAP_PROPERTY = 356,
KW_MAKE_PROPERTY = 357,
KW_MAKE_PROPERTY2 = 358,
KW_MAKE_SEQ = 359,
KW_MAKE_SEQ_PROPERTY = 360,
KW_MUTABLE = 361,
KW_NAMESPACE = 362,
KW_NEW = 363,
KW_NOEXCEPT = 364,
KW_NULLPTR = 365,
KW_OPERATOR = 366,
KW_OVERRIDE = 367,
KW_PRIVATE = 368,
KW_PROTECTED = 369,
KW_PUBLIC = 370,
KW_REGISTER = 371,
KW_REINTERPRET_CAST = 372,
KW_RETURN = 373,
KW_SHORT = 374,
KW_SIGNED = 375,
KW_SIZEOF = 376,
KW_STATIC = 377,
KW_STATIC_ASSERT = 378,
KW_STATIC_CAST = 379,
KW_STRUCT = 380,
KW_TEMPLATE = 381,
KW_THREAD_LOCAL = 382,
KW_THROW = 383,
KW_TRUE = 384,
KW_TRY = 385,
KW_TYPEDEF = 386,
KW_TYPEID = 387,
KW_TYPENAME = 388,
KW_UNDERLYING_TYPE = 389,
KW_UNION = 390,
KW_UNSIGNED = 391,
KW_USING = 392,
KW_VIRTUAL = 393,
KW_VOID = 394,
KW_VOLATILE = 395,
KW_WCHAR_T = 396,
KW_WHILE = 397,
START_CPP = 398,
START_CONST_EXPR = 399,
START_TYPE = 400
KW_MAKE_MAP_KEYS_SEQ = 356,
KW_MAKE_MAP_PROPERTY = 357,
KW_MAKE_PROPERTY = 358,
KW_MAKE_PROPERTY2 = 359,
KW_MAKE_SEQ = 360,
KW_MAKE_SEQ_PROPERTY = 361,
KW_MUTABLE = 362,
KW_NAMESPACE = 363,
KW_NEW = 364,
KW_NOEXCEPT = 365,
KW_NULLPTR = 366,
KW_OPERATOR = 367,
KW_OVERRIDE = 368,
KW_PRIVATE = 369,
KW_PROTECTED = 370,
KW_PUBLIC = 371,
KW_REGISTER = 372,
KW_REINTERPRET_CAST = 373,
KW_RETURN = 374,
KW_SHORT = 375,
KW_SIGNED = 376,
KW_SIZEOF = 377,
KW_STATIC = 378,
KW_STATIC_ASSERT = 379,
KW_STATIC_CAST = 380,
KW_STRUCT = 381,
KW_TEMPLATE = 382,
KW_THREAD_LOCAL = 383,
KW_THROW = 384,
KW_TRUE = 385,
KW_TRY = 386,
KW_TYPEDEF = 387,
KW_TYPEID = 388,
KW_TYPENAME = 389,
KW_UNDERLYING_TYPE = 390,
KW_UNION = 391,
KW_UNSIGNED = 392,
KW_USING = 393,
KW_VIRTUAL = 394,
KW_VOID = 395,
KW_VOLATILE = 396,
KW_WCHAR_T = 397,
KW_WHILE = 398,
START_CPP = 399,
START_CONST_EXPR = 400,
START_TYPE = 401
};
#endif
/* Tokens. */
@ -289,51 +290,52 @@ extern int cppyydebug;
#define KW_IS_TRIVIAL 353
#define KW_IS_UNION 354
#define KW_LONG 355
#define KW_MAKE_MAP_PROPERTY 356
#define KW_MAKE_PROPERTY 357
#define KW_MAKE_PROPERTY2 358
#define KW_MAKE_SEQ 359
#define KW_MAKE_SEQ_PROPERTY 360
#define KW_MUTABLE 361
#define KW_NAMESPACE 362
#define KW_NEW 363
#define KW_NOEXCEPT 364
#define KW_NULLPTR 365
#define KW_OPERATOR 366
#define KW_OVERRIDE 367
#define KW_PRIVATE 368
#define KW_PROTECTED 369
#define KW_PUBLIC 370
#define KW_REGISTER 371
#define KW_REINTERPRET_CAST 372
#define KW_RETURN 373
#define KW_SHORT 374
#define KW_SIGNED 375
#define KW_SIZEOF 376
#define KW_STATIC 377
#define KW_STATIC_ASSERT 378
#define KW_STATIC_CAST 379
#define KW_STRUCT 380
#define KW_TEMPLATE 381
#define KW_THREAD_LOCAL 382
#define KW_THROW 383
#define KW_TRUE 384
#define KW_TRY 385
#define KW_TYPEDEF 386
#define KW_TYPEID 387
#define KW_TYPENAME 388
#define KW_UNDERLYING_TYPE 389
#define KW_UNION 390
#define KW_UNSIGNED 391
#define KW_USING 392
#define KW_VIRTUAL 393
#define KW_VOID 394
#define KW_VOLATILE 395
#define KW_WCHAR_T 396
#define KW_WHILE 397
#define START_CPP 398
#define START_CONST_EXPR 399
#define START_TYPE 400
#define KW_MAKE_MAP_KEYS_SEQ 356
#define KW_MAKE_MAP_PROPERTY 357
#define KW_MAKE_PROPERTY 358
#define KW_MAKE_PROPERTY2 359
#define KW_MAKE_SEQ 360
#define KW_MAKE_SEQ_PROPERTY 361
#define KW_MUTABLE 362
#define KW_NAMESPACE 363
#define KW_NEW 364
#define KW_NOEXCEPT 365
#define KW_NULLPTR 366
#define KW_OPERATOR 367
#define KW_OVERRIDE 368
#define KW_PRIVATE 369
#define KW_PROTECTED 370
#define KW_PUBLIC 371
#define KW_REGISTER 372
#define KW_REINTERPRET_CAST 373
#define KW_RETURN 374
#define KW_SHORT 375
#define KW_SIGNED 376
#define KW_SIZEOF 377
#define KW_STATIC 378
#define KW_STATIC_ASSERT 379
#define KW_STATIC_CAST 380
#define KW_STRUCT 381
#define KW_TEMPLATE 382
#define KW_THREAD_LOCAL 383
#define KW_THROW 384
#define KW_TRUE 385
#define KW_TRY 386
#define KW_TYPEDEF 387
#define KW_TYPEID 388
#define KW_TYPENAME 389
#define KW_UNDERLYING_TYPE 390
#define KW_UNION 391
#define KW_UNSIGNED 392
#define KW_USING 393
#define KW_VIRTUAL 394
#define KW_VOID 395
#define KW_VOLATILE 396
#define KW_WCHAR_T 397
#define KW_WHILE 398
#define START_CPP 399
#define START_CONST_EXPR 400
#define START_TYPE 401
/* Value type. */

View File

@ -304,6 +304,7 @@ pop_struct() {
%token KW_IS_TRIVIAL
%token KW_IS_UNION
%token KW_LONG
%token KW_MAKE_MAP_KEYS_SEQ
%token KW_MAKE_MAP_PROPERTY
%token KW_MAKE_PROPERTY
%token KW_MAKE_PROPERTY2
@ -680,6 +681,49 @@ declaration:
make_property->_del_function = deleter->as_function_group();
}
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
}
| KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
{
CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer);
if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5);
length_getter = NULL;
}
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
getter = nullptr;
}
if (getter != nullptr && length_getter != nullptr) {
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file);
make_property->_get_function = getter->as_function_group();
make_property->_length_function = length_getter->as_function_group();
CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer);
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9);
} else {
make_property->_set_function = setter->as_function_group();
}
CPPDeclaration *deleter = $11->find_symbol(current_scope, global_scope, current_lexer);
if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("reference to non-existent or invalid delete method: " + $11->get_fully_scoped_name(), @11);
} else {
make_property->_del_function = deleter->as_function_group();
}
CPPDeclaration *inserter = $13->find_symbol(current_scope, global_scope, current_lexer);
if (inserter == nullptr || inserter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("reference to non-existent or invalid append method: " + $13->get_fully_scoped_name(), @13);
} else {
make_property->_insert_function = inserter->as_function_group();
}
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
}
@ -751,6 +795,40 @@ declaration:
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
}
| KW_MAKE_MAP_KEYS_SEQ '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';'
{
CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer);
if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5);
length_getter = nullptr;
}
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
yyerror("reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
getter = nullptr;
}
if (getter != nullptr && length_getter != nullptr) {
CPPMakeProperty *make_property = nullptr;
for (size_t i = 0; i < current_scope->_declarations.size(); ++i) {
make_property = current_scope->_declarations[i]->as_make_property();
if (make_property != nullptr) {
if (make_property->get_fully_scoped_name() == $3->get_fully_scoped_name()) {
break;
} else {
make_property = nullptr;
}
}
}
if (make_property != nullptr) {
make_property->_get_key_function = getter->as_function_group();
make_property->_length_function = length_getter->as_function_group();
} else {
yyerror("reference to non-existent MAKE_MAP_PROPERTY: " + $3->get_fully_scoped_name(), @3);
}
}
}
| KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';'
{

View File

@ -28,7 +28,9 @@ CPPMakeProperty(CPPIdentifier *ident, Type type,
_get_function(nullptr),
_set_function(nullptr),
_clear_function(nullptr),
_del_function(nullptr)
_del_function(nullptr),
_insert_function(nullptr),
_get_key_function(nullptr)
{
_ident->_native_scope = current_scope;
}
@ -96,6 +98,10 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
out << ", " << _del_function->_name;
}
if (_insert_function != NULL) {
out << ", " << _insert_function->_name;
}
out << ");";
}

View File

@ -109,6 +109,8 @@ public:
CPPFunctionGroup *_set_function;
CPPFunctionGroup *_clear_function;
CPPFunctionGroup *_del_function;
CPPFunctionGroup *_insert_function;
CPPFunctionGroup *_get_key_function;
};
#endif

View File

@ -2641,6 +2641,7 @@ check_keyword(const string &name) {
if (name == "__is_trivial") return KW_IS_TRIVIAL;
if (name == "__is_union") return KW_IS_UNION;
if (name == "long") return KW_LONG;
if (name == "__make_map_keys_seq") return KW_MAKE_MAP_KEYS_SEQ;
if (name == "__make_map_property") return KW_MAKE_MAP_PROPERTY;
if (name == "__make_property") return KW_MAKE_PROPERTY;
if (name == "__make_property2") return KW_MAKE_PROPERTY2;

View File

@ -465,6 +465,7 @@ typedef struct _object PyObject;
#define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
#define MAKE_SEQ_PROPERTY(property_name, ...) __make_seq_property(property_name, __VA_ARGS__)
#define MAKE_MAP_PROPERTY(property_name, ...) __make_map_property(property_name, __VA_ARGS__)
#define MAKE_MAP_KEYS_SEQ(property_name, ...) __make_map_keys_seq(property_name, __VA_ARGS__)
#define EXTENSION(x) __extension x
#define EXTEND __extension
#else
@ -476,6 +477,7 @@ typedef struct _object PyObject;
#define MAKE_SEQ(seq_name, num_name, element_name)
#define MAKE_SEQ_PROPERTY(property_name, ...)
#define MAKE_MAP_PROPERTY(property_name, ...)
#define MAKE_MAP_KEYS_SEQ(property_name, ...)
#define EXTENSION(x)
#define EXTEND
#endif

View File

@ -47,7 +47,9 @@ static_assert(MEMORY_HOOK_ALIGNMENT * 8 >= NATIVE_WORDSIZE,
static_assert((MEMORY_HOOK_ALIGNMENT & (MEMORY_HOOK_ALIGNMENT - 1)) == 0,
"MEMORY_HOOK_ALIGNMENT should be a power of two");
#if defined(USE_MEMORY_DLMALLOC)
#if defined(CPPPARSER)
#elif defined(USE_MEMORY_DLMALLOC)
// Memory manager: DLMALLOC This is Doug Lea's memory manager. It is very
// fast, but it is not thread-safe. However, we provide thread locking within

View File

@ -90,6 +90,8 @@ Property(const InterrogateElement &ielement) :
_has_function(nullptr),
_clear_function(nullptr),
_deleter(nullptr),
_inserter(nullptr),
_getkey_function(nullptr),
_has_this(false)
{
}

View File

@ -132,6 +132,8 @@ public:
Function *_has_function;
Function *_clear_function;
Function *_deleter;
Function *_inserter;
Function *_getkey_function;
bool _has_this;
};
typedef vector<Property *> Properties;

View File

@ -6391,6 +6391,8 @@ write_getset(ostream &out, Object *obj, Property *property) {
FunctionRemap *len_remap = nullptr;
if (property->_length_function != nullptr) {
assert(!property->_length_function->_remaps.empty());
// This is actually a sequence. Wrap this with a special class.
len_remap = property->_length_function->_remaps.front();
@ -6416,6 +6418,7 @@ write_getset(ostream &out, Object *obj, Property *property) {
}
if (ielem.is_sequence()) {
assert(len_remap != nullptr);
out <<
"/**\n"
" * sequence getter for property " << ielem.get_scoped_name() << "\n"
@ -6543,6 +6546,35 @@ write_getset(ostream &out, Object *obj, Property *property) {
out << " return -1;\n";
out << "}\n\n";
}
// Finally, add the inserter, if one exists.
if (property->_inserter != nullptr) {
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Sequence_insert(PyObject *self, size_t index, PyObject *arg) {\n";
if (property->_has_this) {
out << " " << cClassName << " *local_this = NULL;\n";
out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \""
<< classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n";
out << " return NULL;\n";
out << " }\n\n";
}
std::set<FunctionRemap*> remaps;
remaps.insert(property->_inserter->_remaps.begin(),
property->_inserter->_remaps.end());
string expected_params;
write_function_forset(out, remaps, 2, 2,
expected_params, 2, true, true, AT_single_arg,
RF_pyobject | RF_err_null, false, false, "index");
out << " if (!_PyErr_OCCURRED()) {\n";
out << " Dtool_Raise_BadArgumentsError(\n";
output_quoted(out, 6, expected_params);
out << ");\n";
out << " }\n";
out << " return NULL;\n";
out << "}\n\n";
}
}
@ -6674,7 +6706,7 @@ write_getset(ostream &out, Object *obj, Property *property) {
remaps.insert(property->_setter_remaps.begin(),
property->_setter_remaps.end());
// We have to create an args tuple only to unpack it alter, ugh.
// We have to create an args tuple only to unpack it later, ugh.
out << " PyObject *args = PyTuple_New(2);\n"
<< " PyTuple_SET_ITEM(args, 0, key);\n"
<< " PyTuple_SET_ITEM(args, 1, value);\n"
@ -6695,86 +6727,117 @@ write_getset(ostream &out, Object *obj, Property *property) {
out << " return -1;\n";
out << "}\n\n";
}
if (property->_getkey_function != nullptr) {
out <<
"/**\n"
" * mapping key-getter for property " << ielem.get_scoped_name() << "\n"
" */\n"
"static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Mapping_Getkey(PyObject *self, Py_ssize_t index) {\n";
if (property->_has_this) {
out <<
" " << cClassName << " *local_this = NULL;\n"
" if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
" return NULL;\n"
" }\n";
}
// We need to raise IndexError if we're out of bounds.
if (len_remap != nullptr) {
out << " if (index < 0 || index >= (Py_ssize_t)"
<< len_remap->get_call_str("local_this", pexprs) << ") {\n";
out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << "." << ielem.get_name() << "[] index out of range\");\n";
out << " return NULL;\n";
out << " }\n";
}
std::set<FunctionRemap*> remaps;
// Extract only the getters that take one integral argument.
Function::Remaps::iterator it;
for (it = property->_getkey_function->_remaps.begin();
it != property->_getkey_function->_remaps.end();
++it) {
FunctionRemap *remap = *it;
int min_num_args = remap->get_min_num_args();
int max_num_args = remap->get_max_num_args();
if (min_num_args <= 1 && max_num_args >= 1 &&
TypeManager::is_integer(remap->_parameters[(size_t)remap->_has_this]._remap->get_new_type())) {
remaps.insert(remap);
}
}
string expected_params;
write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
AT_no_args, RF_pyobject | RF_err_null, false, true, "index");
out << " if (!_PyErr_OCCURRED()) {\n";
out << " return Dtool_Raise_BadArgumentsError(\n";
output_quoted(out, 6, expected_params);
out << ");\n"
" }\n"
"}\n\n";
}
}
// Now write the actual getter wrapper. It will be a different wrapper
// depending on whether it's a mapping, sequence, or both.
if (ielem.is_mapping() && ielem.is_sequence()) {
// depending on whether it's a mapping or a sequence.
if (ielem.is_mapping()) {
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
if (property->_has_this) {
out << " nassertr(self != NULL, NULL);\n"
" Py_INCREF(self);\n";
} else {
out << " Py_XINCREF(self);\n";
out << " nassertr(self != NULL, NULL);\n";
}
out << " Dtool_SeqMapWrapper *wrap = PyObject_New(Dtool_SeqMapWrapper, &Dtool_SeqMapWrapper_Type);\n"
" wrap->_map._base._self = self;\n"
" wrap->_map._base._name = \"" << ClassName << "." << ielem.get_name() << "\";\n"
" wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"
" wrap->_seq_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n"
" wrap->_map._getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getitem;\n";
if (property->_setter_remaps.empty()) {
out << " Dtool_MappingWrapper *wrap = Dtool_NewMappingWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n";
} else {
out << " Dtool_MappingWrapper *wrap = Dtool_NewMutableMappingWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n";
}
out << " if (wrap != NULL) {\n"
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getitem;\n";
if (!property->_setter_remaps.empty()) {
out << " if (!((Dtool_PyInstDef *)self)->_is_const) {\n"
" wrap->_seq_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Setitem;\n"
" wrap->_map._setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Setitem;\n"
" } else {\n"
" wrap->_seq_setitem_func = NULL;\n"
" wrap->_map._setitem_func = NULL;\n"
" }\n";
} else {
out << " wrap->_seq_setitem_func = NULL;\n";
out << " wrap->_map._setitem_func = NULL;\n";
out << " if (!((Dtool_PyInstDef *)self)->_is_const) {\n";
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Setitem;\n";
out << " }\n";
}
out << " return (PyObject *)wrap;\n"
if (property->_length_function != nullptr) {
out << " wrap->_keys._len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n";
if (property->_getkey_function != nullptr) {
out << " wrap->_keys._getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getkey;\n";
}
}
out << " }\n"
" return (PyObject *)wrap;\n"
"}\n\n";
} else if (ielem.is_mapping()) {
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
if (property->_has_this) {
out << " nassertr(self != NULL, NULL);\n"
" Py_INCREF(self);\n";
} else {
out << " Py_XINCREF(self);\n";
}
out << " Dtool_MappingWrapper *wrap = PyObject_New(Dtool_MappingWrapper, &Dtool_MappingWrapper_Type);\n"
" wrap->_base._self = self;\n"
" wrap->_base._name = \"" << ClassName << "." << ielem.get_name() << "\";\n"
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getitem;\n";
if (!property->_setter_remaps.empty()) {
out << " if (!((Dtool_PyInstDef *)self)->_is_const) {\n";
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Setitem;\n";
out << " } else {\n";
out << " wrap->_setitem_func = NULL;\n";
out << " }\n";
} else {
out << " wrap->_setitem_func = NULL;\n";
}
out << " return (PyObject *)wrap;\n"
"}\n\n";
} else if (ielem.is_sequence()) {
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
if (property->_has_this) {
out << " nassertr(self != NULL, NULL);\n"
" Py_INCREF(self);\n";
} else {
out << " Py_XINCREF(self);\n";
out << " nassertr(self != NULL, NULL);\n";
}
out << " Dtool_SequenceWrapper *wrap = PyObject_New(Dtool_SequenceWrapper, &Dtool_SequenceWrapper_Type);\n"
" wrap->_base._self = self;\n"
" wrap->_base._name = \"" << ClassName << "." << ielem.get_name() << "\";\n"
" wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n";
if (!property->_setter_remaps.empty()) {
out << " if (!((Dtool_PyInstDef *)self)->_is_const) {\n";
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Setitem;\n";
out << " } else {\n";
out << " wrap->_setitem_func = NULL;\n";
out << " }\n";
if (property->_setter_remaps.empty()) {
out <<
" Dtool_SequenceWrapper *wrap = Dtool_NewSequenceWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n"
" if (wrap != NULL) {\n"
" wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n";
} else {
out << " wrap->_setitem_func = NULL;\n";
out <<
" Dtool_MutableSequenceWrapper *wrap = Dtool_NewMutableSequenceWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n"
" if (wrap != NULL) {\n"
" wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n";
if (!property->_setter_remaps.empty()) {
out << " if (!((Dtool_PyInstDef *)self)->_is_const) {\n";
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Setitem;\n";
if (property->_inserter != nullptr) {
out << " wrap->_insert_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_insert;\n";
}
out << " }\n";
}
}
out << " return (PyObject *)wrap;\n"
out << " }\n"
" return (PyObject *)wrap;\n"
"}\n\n";
} else {
@ -7083,9 +7146,30 @@ record_property(const InterrogateType &itype, ElementIndex element_index) {
}
}
if (ielement.is_sequence()) {
if (ielement.is_sequence() || ielement.is_mapping()) {
FunctionIndex func_index = ielement.get_length_function();
property->_length_function = record_function(itype, func_index);
if (func_index != 0) {
property->_length_function = record_function(itype, func_index);
}
}
if (ielement.is_sequence() && ielement.has_insert_function()) {
FunctionIndex func_index = ielement.get_insert_function();
Function *insert_function = record_function(itype, func_index);
if (is_function_legal(insert_function)) {
property->_inserter = insert_function;
property->_has_this |= insert_function->_has_this;
}
}
if (ielement.is_mapping() && ielement.has_getkey_function()) {
FunctionIndex func_index = ielement.get_getkey_function();
assert(func_index != 0);
Function *getkey_function = record_function(itype, func_index);
if (is_function_legal(getkey_function)) {
property->_getkey_function = getkey_function;
property->_has_this |= getkey_function->_has_this;
}
}
return property;

View File

@ -1824,20 +1824,17 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
// If we have a length function (ie. this is a sequence property), we should
// find the function that will give us the length.
FunctionIndex length_function = 0;
if (make_property->_type & CPPMakeProperty::T_sequence) {
CPPFunctionGroup *fgroup = make_property->_length_function;
if (fgroup != nullptr) {
CPPFunctionGroup::Instances::const_iterator fi;
CPPFunctionGroup *fgroup = make_property->_length_function;
if (fgroup != NULL) {
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
CPPInstance *function = (*fi);
CPPFunctionType *ftype =
function->_type->as_function_type();
if (ftype != NULL) {
length_function = get_function(function, "", struct_type,
struct_type->get_scope(), 0);
if (length_function != 0) {
break;
}
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
CPPInstance *function = (*fi);
CPPFunctionType *ftype = function->_type->as_function_type();
if (ftype != nullptr) {
length_function = get_function(function, "", struct_type,
struct_type->get_scope(), 0);
if (length_function != 0) {
break;
}
}
}
@ -1855,7 +1852,7 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
// How many arguments we expect the getter to have.
size_t num_args = (size_t)(make_property->_type != CPPMakeProperty::T_normal);
CPPFunctionGroup *fgroup = make_property->_get_function;
fgroup = make_property->_get_function;
if (fgroup != NULL) {
CPPFunctionGroup::Instances::const_iterator fi;
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
@ -1942,9 +1939,13 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
CPPInstance *function = (*fi);
CPPFunctionType *ftype = function->_type->as_function_type();
if (ftype != NULL && ftype->_parameters->_parameters.size() == num_args) {
deleter = function;
break;
if (ftype != nullptr) {
const CPPParameterList::Parameters &params = ftype->_parameters->_parameters;
if (params.size() == num_args ||
(params.size() > num_args && params[num_args]->_initializer != nullptr)) {
deleter = function;
break;
}
}
}
@ -1955,6 +1956,50 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
}
}
// And the "inserter".
CPPInstance *inserter = nullptr;
fgroup = make_property->_insert_function;
if (fgroup != nullptr) {
CPPFunctionGroup::Instances::const_iterator fi;
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
CPPInstance *function = (*fi);
CPPFunctionType *ftype = function->_type->as_function_type();
if (ftype != nullptr && ftype->_parameters->_parameters.size() == 2) {
inserter = function;
break;
}
}
if (inserter == nullptr) {
cerr << "No instance of insert-function '"
<< fgroup->_name << "' is suitable!\n";
return 0;
}
}
// And the function that returns a key by index.
CPPInstance *getkey_function = nullptr;
fgroup = make_property->_get_key_function;
if (fgroup != nullptr) {
CPPFunctionGroup::Instances::const_iterator fi;
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
CPPInstance *function = (*fi);
CPPFunctionType *ftype = function->_type->as_function_type();
if (ftype != nullptr) {
getkey_function = function;
break;
}
}
if (getkey_function == nullptr) {
cerr << "No instance of get-key-function '"
<< fgroup->_name << "' is suitable!\n";
return 0;
}
}
if (index == 0) {
// It isn't here, so we'll have to define it.
index = idb->get_next_index();
@ -1980,10 +2025,12 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
if (make_property->_type & CPPMakeProperty::T_sequence) {
iproperty._flags |= InterrogateElement::F_sequence;
iproperty._length_function = length_function;
assert(length_function != 0);
}
if (make_property->_type & CPPMakeProperty::T_mapping) {
iproperty._flags |= InterrogateElement::F_mapping;
iproperty._length_function = length_function;
}
if (make_property->_type == CPPMakeProperty::T_normal) {
@ -2029,6 +2076,20 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
nassertr(iproperty._del_function, 0);
}
if (inserter != NULL) {
iproperty._flags |= InterrogateElement::F_has_insert_function;
iproperty._insert_function = get_function(inserter, "", struct_type,
struct_type->get_scope(), 0);
nassertr(iproperty._insert_function, 0);
}
if (getkey_function != NULL) {
iproperty._flags |= InterrogateElement::F_has_getkey_function;
iproperty._getkey_function = get_function(getkey_function, "", struct_type,
struct_type->get_scope(), 0);
nassertr(iproperty._getkey_function, 0);
}
// See if there happens to be a comment before the MAKE_PROPERTY macro.
if (make_property->_leading_comment != (CPPCommentBlock *)NULL) {
iproperty._comment = trim_blanks(make_property->_leading_comment->_comment);

View File

@ -20,7 +20,7 @@ InterrogateDatabase *InterrogateDatabase::_global_ptr = NULL;
int InterrogateDatabase::_file_major_version = 0;
int InterrogateDatabase::_file_minor_version = 0;
int InterrogateDatabase::_current_major_version = 3;
int InterrogateDatabase::_current_minor_version = 2;
int InterrogateDatabase::_current_minor_version = 3;
/**
*

View File

@ -25,6 +25,8 @@ InterrogateElement(InterrogateModuleDef *def) :
_has_function = 0;
_clear_function = 0;
_del_function = 0;
_insert_function = 0;
_getkey_function = 0;
_length_function = 0;
_make_property = nullptr;
}
@ -52,6 +54,8 @@ operator = (const InterrogateElement &copy) {
_has_function = copy._has_function;
_clear_function = copy._clear_function;
_del_function = copy._del_function;
_insert_function = copy._insert_function;
_getkey_function = copy._getkey_function;
_length_function = copy._length_function;
_make_property = copy._make_property;
}
@ -185,6 +189,38 @@ get_del_function() const {
return _del_function;
}
/**
*
*/
INLINE bool InterrogateElement::
has_insert_function() const {
return (_flags & F_has_insert_function) != 0;
}
/**
*
*/
INLINE FunctionIndex InterrogateElement::
get_insert_function() const {
return _insert_function;
}
/**
*
*/
INLINE bool InterrogateElement::
has_getkey_function() const {
return (_flags & F_has_getkey_function) != 0;
}
/**
*
*/
INLINE FunctionIndex InterrogateElement::
get_getkey_function() const {
return _getkey_function;
}
/**
*
*/

View File

@ -29,7 +29,9 @@ output(ostream &out) const {
<< _has_function << " "
<< _clear_function << " "
<< _del_function << " "
<< _length_function << " ";
<< _length_function << " "
<< _insert_function << " "
<< _getkey_function << " ";
idf_output_string(out, _scoped_name);
idf_output_string(out, _comment, '\n');
}
@ -45,6 +47,9 @@ input(istream &in) {
in >> _has_function >> _clear_function;
if (InterrogateDatabase::get_file_minor_version() >= 2) {
in >> _del_function >> _length_function;
if (InterrogateDatabase::get_file_minor_version() >= 3) {
in >> _insert_function >> _getkey_function;
}
}
}
idf_input_string(in, _scoped_name);
@ -63,5 +68,7 @@ remap_indices(const IndexRemapper &remap) {
_has_function = remap.map_from(_has_function);
_clear_function = remap.map_from(_clear_function);
_del_function = remap.map_from(_del_function);
_insert_function = remap.map_from(_insert_function);
_getkey_function = remap.map_from(_getkey_function);
_length_function = remap.map_from(_length_function);
}

View File

@ -50,6 +50,10 @@ public:
INLINE FunctionIndex get_clear_function() const;
INLINE bool has_del_function() const;
INLINE FunctionIndex get_del_function() const;
INLINE bool has_insert_function() const;
INLINE FunctionIndex get_insert_function() const;
INLINE bool has_getkey_function() const;
INLINE FunctionIndex get_getkey_function() const;
INLINE bool is_sequence() const;
INLINE FunctionIndex get_length_function() const;
INLINE bool is_mapping() const;
@ -69,6 +73,8 @@ private:
F_has_del_function= 0x0020,
F_sequence = 0x0040,
F_mapping = 0x0080,
F_has_insert_function= 0x0100,
F_has_getkey_function= 0x0200,
};
int _flags;
@ -81,6 +87,8 @@ private:
FunctionIndex _has_function;
FunctionIndex _clear_function;
FunctionIndex _del_function;
FunctionIndex _insert_function;
FunctionIndex _getkey_function;
CPPMakeProperty *_make_property;

View File

@ -5,7 +5,4 @@
#include "interrogate_interface.cxx"
#include "interrogate_request.cxx"
#include "py_panda.cxx"
#include "py_wrappers.cxx"

View File

@ -614,12 +614,28 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_SequenceWrapper)");
}
if (PyType_Ready(&Dtool_MutableSequenceWrapper_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MutableSequenceWrapper)");
}
if (PyType_Ready(&Dtool_MappingWrapper_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper)");
}
if (PyType_Ready(&Dtool_SeqMapWrapper_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_SeqMapWrapper)");
if (PyType_Ready(&Dtool_MutableMappingWrapper_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MutableMappingWrapper)");
}
if (PyType_Ready(&Dtool_MappingWrapper_Keys_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper_Keys)");
}
if (PyType_Ready(&Dtool_MappingWrapper_Values_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper_Values)");
}
if (PyType_Ready(&Dtool_MappingWrapper_Items_Type) < 0) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper_Items)");
}
if (PyType_Ready(&Dtool_GeneratorWrapper_Type) < 0) {
@ -1039,957 +1055,4 @@ bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds)
return (PyTuple_GET_SIZE(args) == 0);
}
/**
* These classes are returned from properties that require a subscript
* interface, ie. something.children[i] = 3.
*/
static void Dtool_WrapperBase_dealloc(PyObject *self) {
Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
nassertv(wrap);
Py_XDECREF(wrap->_self);
}
static PyObject *Dtool_WrapperBase_repr(PyObject *self) {
Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
nassertr(wrap, nullptr);
PyObject *repr = PyObject_Repr(wrap->_self);
PyObject *result;
#if PY_MAJOR_VERSION >= 3
result = PyUnicode_FromFormat("<%s[] of %s>", wrap->_name, PyUnicode_AsUTF8(repr));
#else
result = PyString_FromFormat("<%s[] of %s>", wrap->_name, PyString_AS_STRING(repr));
#endif
Py_DECREF(repr);
return result;
}
static PyObject *Dtool_SequenceWrapper_repr(PyObject *self) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
Py_ssize_t len = -1;
if (wrap->_len_func != nullptr) {
len = wrap->_len_func(wrap->_base._self);
}
if (len < 0) {
PyErr_Restore(nullptr, nullptr, nullptr);
return Dtool_WrapperBase_repr(self);
}
PyObject *repr = PyObject_Repr(wrap->_base._self);
PyObject *result;
#if PY_MAJOR_VERSION >= 3
result = PyUnicode_FromFormat("<%s[%zd] of %s>", wrap->_base._name, len, PyUnicode_AsUTF8(repr));
#else
result = PyString_FromFormat("<%s[%zd] of %s>", wrap->_base._name, len, PyString_AS_STRING(repr));
#endif
Py_DECREF(repr);
return result;
}
static Py_ssize_t Dtool_SequenceWrapper_length(PyObject *self) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, -1);
if (wrap->_len_func != nullptr) {
return wrap->_len_func(wrap->_base._self);
} else {
Dtool_Raise_TypeError("property does not support len()");
return -1;
}
}
static PyObject *Dtool_SequenceWrapper_getitem(PyObject *self, Py_ssize_t index) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
nassertr(wrap->_getitem_func, nullptr);
return wrap->_getitem_func(wrap->_base._self, index);
}
static int Dtool_SequenceWrapper_setitem(PyObject *self, Py_ssize_t index, PyObject *value) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, -1);
if (wrap->_setitem_func != nullptr) {
return wrap->_setitem_func(wrap->_base._self, index, value);
} else {
Dtool_Raise_TypeError("property does not support item assignment");
return -1;
}
}
/**
* Implementation of property.index(x) which returns the index of the first
* occurrence of x in the sequence, or raises a ValueError if it isn't found.
*/
static PyObject *Dtool_SequenceWrapper_index(PyObject *self, PyObject *value) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
Py_ssize_t length = 0;
if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) {
length = wrap->_len_func(wrap->_base._self);
} else {
return Dtool_Raise_TypeError("property does not support remove()");
}
// Iterate through the items, invoking the equality function for each, until
// we have found the right one.
nassertr(wrap->_getitem_func, nullptr);
for (Py_ssize_t index = 0; index < length; ++index) {
PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
if (item != nullptr) {
int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
if (cmp > 0) {
return Dtool_WrapValue(index);
}
if (cmp < 0) {
return nullptr;
}
} else {
return nullptr;
}
}
// Not found, raise ValueError.
return PyErr_Format(PyExc_ValueError, "%s.index() did not find value", wrap->_base._name);
}
/**
* Implementation of property.count(x) which returns the number of occurrences
* of x in the sequence.
*/
static PyObject *Dtool_SequenceWrapper_count(PyObject *self, PyObject *value) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
Py_ssize_t index = 0;
if (wrap->_len_func != nullptr) {
index = wrap->_len_func(wrap->_base._self);
} else {
return Dtool_Raise_TypeError("property does not support count()");
}
// Iterate through the items, invoking the == operator for each.
long count = 0;
nassertr(wrap->_getitem_func, nullptr);
while (index > 0) {
--index;
PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
if (item == nullptr) {
return nullptr;
}
int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
if (cmp > 0) {
++count;
}
if (cmp < 0) {
return nullptr;
}
}
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(count);
#else
return PyInt_FromLong(count);
#endif
}
/**
* Implementation of property.clear() which removes all elements in the
* sequence, starting with the last.
*/
static PyObject *Dtool_SequenceWrapper_clear(PyObject *self, PyObject *) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
Py_ssize_t index = 0;
if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) {
index = wrap->_len_func(wrap->_base._self);
} else {
return Dtool_Raise_TypeError("property does not support clear()");
}
// Iterate through the items, invoking the delete function for each. We do
// this in reverse order, which may be more efficient.
while (index > 0) {
--index;
if (wrap->_setitem_func(wrap->_base._self, index, nullptr) != 0) {
return nullptr;
}
}
Py_INCREF(Py_None);
return Py_None;
}
/**
* Implementation of property.remove(x) which removes the first occurrence of
* x in the sequence, or raises a ValueError if it isn't found.
*/
static PyObject *Dtool_SequenceWrapper_remove(PyObject *self, PyObject *value) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
Py_ssize_t length = 0;
if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) {
length = wrap->_len_func(wrap->_base._self);
} else {
return Dtool_Raise_TypeError("property does not support remove()");
}
// Iterate through the items, invoking the equality function for each, until
// we have found the right one.
nassertr(wrap->_getitem_func, nullptr);
for (Py_ssize_t index = 0; index < length; ++index) {
PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
if (item != nullptr) {
int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
if (cmp > 0) {
if (wrap->_setitem_func(wrap->_base._self, index, nullptr) == 0) {
Py_INCREF(Py_None);
return Py_None;
} else {
return nullptr;
}
}
if (cmp < 0) {
return nullptr;
}
} else {
return nullptr;
}
}
// Not found, raise ValueError.
return PyErr_Format(PyExc_ValueError, "%s.remove() did not find value", wrap->_base._name);
}
/**
* Implementation of property.pop([i=-1]) which returns and removes the
* element at the indicated index in the sequence. If no index is provided,
* it removes from the end of the list.
*/
static PyObject *Dtool_SequenceWrapper_pop(PyObject *self, PyObject *args) {
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
nassertr(wrap, nullptr);
if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr ||
wrap->_len_func == nullptr) {
return Dtool_Raise_TypeError("property does not support pop()");
}
Py_ssize_t length = wrap->_len_func(wrap->_base._self);
Py_ssize_t index;
switch (PyTuple_GET_SIZE(args)) {
case 0:
index = length - 1;
break;
case 1:
index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 0), PyExc_IndexError);
if (index == -1 && _PyErr_OCCURRED()) {
return nullptr;
}
if (index < 0) {
index += length;
}
break;
default:
return Dtool_Raise_TypeError("pop([i=-1]) takes 0 or 1 arguments");
}
if (length <= 0) {
return PyErr_Format(PyExc_IndexError, "%s.pop() from empty sequence", wrap->_base._name);
}
// Index error will be caught by getitem_func.
PyObject *value = wrap->_getitem_func(wrap->_base._self, index);
if (value != nullptr) {
if (wrap->_setitem_func(wrap->_base._self, index, nullptr) != 0) {
return nullptr;
}
return value;
}
return nullptr;
}
static int Dtool_MappingWrapper_contains(PyObject *self, PyObject *key) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, -1);
nassertr(wrap->_getitem_func, -1);
PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
if (value != nullptr) {
Py_DECREF(value);
return 1;
} else if (_PyErr_OCCURRED() == PyExc_KeyError ||
_PyErr_OCCURRED() == PyExc_TypeError) {
PyErr_Restore(nullptr, nullptr, nullptr);
return 0;
} else {
return -1;
}
}
static PyObject *Dtool_MappingWrapper_getitem(PyObject *self, PyObject *key) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, nullptr);
nassertr(wrap->_getitem_func, nullptr);
return wrap->_getitem_func(wrap->_base._self, key);
}
static int Dtool_MappingWrapper_setitem(PyObject *self, PyObject *key, PyObject *value) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, -1);
if (wrap->_setitem_func != nullptr) {
return wrap->_setitem_func(wrap->_base._self, key, value);
} else {
Dtool_Raise_TypeError("property does not support item assignment");
return -1;
}
}
/**
* Implementation of property.get(key[,def=None]) which returns the value with
* the given key in the mapping, or the given default value (which defaults to
* None) if the key isn't found in the mapping.
*/
static PyObject *Dtool_MappingWrapper_get(PyObject *self, PyObject *args) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, nullptr);
nassertr(wrap->_getitem_func, nullptr);
Py_ssize_t size = PyTuple_GET_SIZE(args);
if (size != 1 && size != 2) {
return PyErr_Format(PyExc_TypeError, "%s.get() takes 1 or 2 arguments", wrap->_base._name);
}
PyObject *defvalue = Py_None;
if (size >= 2) {
defvalue = PyTuple_GET_ITEM(args, 1);
}
PyObject *key = PyTuple_GET_ITEM(args, 0);
PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
if (value != nullptr) {
return value;
} else if (_PyErr_OCCURRED() == PyExc_KeyError) {
PyErr_Restore(nullptr, nullptr, nullptr);
Py_INCREF(defvalue);
return defvalue;
} else {
return nullptr;
}
}
/**
* Implementation of property.pop(key[,def=None]) which is the same as get()
* except that it also removes the element from the mapping.
*/
static PyObject *Dtool_MappingWrapper_pop(PyObject *self, PyObject *args) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, nullptr);
if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) {
return Dtool_Raise_TypeError("property does not support pop()");
}
Py_ssize_t size = PyTuple_GET_SIZE(args);
if (size != 1 && size != 2) {
return PyErr_Format(PyExc_TypeError, "%s.pop() takes 1 or 2 arguments", wrap->_base._name);
}
PyObject *defvalue = Py_None;
if (size >= 2) {
defvalue = PyTuple_GET_ITEM(args, 1);
}
PyObject *key = PyTuple_GET_ITEM(args, 0);
PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
if (value != nullptr) {
// OK, now set unset this value.
if (wrap->_setitem_func(wrap->_base._self, key, nullptr) == 0) {
return value;
} else {
Py_DECREF(value);
return nullptr;
}
} else if (_PyErr_OCCURRED() == PyExc_KeyError) {
PyErr_Restore(nullptr, nullptr, nullptr);
Py_INCREF(defvalue);
return defvalue;
} else {
return nullptr;
}
}
/**
* Implementation of property.setdefault(key[,def=None]) which is the same as
* get() except that it also writes the default value back to the mapping if
* the key was not found is missing.
*/
static PyObject *Dtool_MappingWrapper_setdefault(PyObject *self, PyObject *args) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, nullptr);
if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) {
return Dtool_Raise_TypeError("property does not support setdefault()");
}
Py_ssize_t size = PyTuple_GET_SIZE(args);
if (size != 1 && size != 2) {
return PyErr_Format(PyExc_TypeError, "%s.setdefault() takes 1 or 2 arguments", wrap->_base._name);
}
PyObject *defvalue = Py_None;
if (size >= 2) {
defvalue = PyTuple_GET_ITEM(args, 1);
}
PyObject *key = PyTuple_GET_ITEM(args, 0);
PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
if (value != nullptr) {
return value;
} else if (_PyErr_OCCURRED() == PyExc_KeyError) {
PyErr_Restore(nullptr, nullptr, nullptr);
if (wrap->_setitem_func(wrap->_base._self, key, defvalue) == 0) {
Py_INCREF(defvalue);
return defvalue;
}
}
return nullptr;
}
/**
* Implementation of property.update(...) which sets multiple values in one
* go. It accepts either a single dictionary or keyword arguments, not both.
*/
static PyObject *Dtool_MappingWrapper_update(PyObject *self, PyObject *args, PyObject *kwargs) {
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
nassertr(wrap, nullptr);
if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) {
return Dtool_Raise_TypeError("property does not support update()");
}
// We accept either a dict argument or keyword arguments, but not both.
PyObject *dict;
switch (PyTuple_GET_SIZE(args)) {
case 0:
if (kwargs == nullptr) {
// This is legal.
Py_INCREF(Py_None);
return Py_None;
}
dict = kwargs;
break;
case 1:
if (PyDict_Check(PyTuple_GET_ITEM(args, 0)) && (kwargs == nullptr || Py_SIZE(kwargs) == 0)) {
dict = PyTuple_GET_ITEM(args, 0);
break;
}
// Fall through
default:
return PyErr_Format(PyExc_TypeError, "%s.update() takes either a dict argument or keyword arguments", wrap->_base._name);
}
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(dict, &pos, &key, &value)) {
if (wrap->_setitem_func(wrap->_base._self, key, value) != 0) {
return nullptr;
}
}
Py_INCREF(Py_None);
return Py_None;
}
/**
* Implementation of len(property) for mapping types.
*/
static Py_ssize_t Dtool_SeqMapWrapper_length(PyObject *self) {
Dtool_SeqMapWrapper *wrap = (Dtool_SeqMapWrapper *)self;
nassertr(wrap, -1);
if (wrap->_len_func != nullptr) {
return wrap->_len_func(wrap->_map._base._self);
} else {
Dtool_Raise_TypeError("property does not support len()");
return -1;
}
}
/**
* Implementation of property.values() which returns a tuple containing the
* dictionary values.
*/
static PyObject *Dtool_SeqMapWrapper_values(PyObject *self, PyObject *) {
Dtool_SeqMapWrapper *wrap = (Dtool_SeqMapWrapper *)self;
nassertr(wrap, nullptr);
nassertr(wrap->_len_func, nullptr);
nassertr(wrap->_seq_getitem_func, nullptr);
Py_ssize_t length = wrap->_len_func(wrap->_map._base._self);
PyObject *values = PyTuple_New(length);
if (UNLIKELY(values == nullptr)) {
return nullptr;
}
for (Py_ssize_t i = 0; i < length; ++i) {
PyObject *value = wrap->_seq_getitem_func(wrap->_map._base._self, i);
if (value != nullptr) {
PyTuple_SET_ITEM(values, i, value);
} else {
Py_DECREF(values);
return nullptr;
}
}
return values;
}
/**
* This variant defines only a sequence interface.
*/
static PySequenceMethods Dtool_SequenceWrapper_SequenceMethods = {
Dtool_SequenceWrapper_length,
0, // sq_concat
0, // sq_repeat
Dtool_SequenceWrapper_getitem,
0, // sq_slice
Dtool_SequenceWrapper_setitem,
0, // sq_ass_slice
0, // sq_contains
0, // sq_inplace_concat
0, // sq_inplace_repeat
};
static PyMethodDef Dtool_SequenceWrapper_Methods[] = {
{"index", &Dtool_SequenceWrapper_index, METH_O, nullptr},
{"count", &Dtool_SequenceWrapper_count, METH_O, nullptr},
{"clear", &Dtool_SequenceWrapper_clear, METH_NOARGS, nullptr},
{"pop", &Dtool_SequenceWrapper_pop, METH_VARARGS, nullptr},
{"remove", &Dtool_SequenceWrapper_remove, METH_O, nullptr},
{nullptr, nullptr, 0, nullptr}
};
PyTypeObject Dtool_SequenceWrapper_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"sequence wrapper",
sizeof(Dtool_SequenceWrapper),
0, // tp_itemsize
Dtool_WrapperBase_dealloc,
0, // tp_print
0, // tp_getattr
0, // tp_setattr
#if PY_MAJOR_VERSION >= 3
0, // tp_reserved
#else
0, // tp_compare
#endif
Dtool_SequenceWrapper_repr,
0, // tp_as_number
&Dtool_SequenceWrapper_SequenceMethods,
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
PyObject_GenericGetAttr,
PyObject_GenericSetAttr,
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
Dtool_SequenceWrapper_Methods,
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
PyType_GenericAlloc,
0, // tp_new
PyObject_Del,
0, // tp_is_gc
0, // tp_bases
0, // tp_mro
0, // tp_cache
0, // tp_subclasses
0, // tp_weaklist
0, // tp_del
#if PY_VERSION_HEX >= 0x02060000
0, // tp_version_tag
#endif
#if PY_VERSION_HEX >= 0x03040000
0, // tp_finalize
#endif
};
/**
* This variant defines only a mapping interface.
*/
static PySequenceMethods Dtool_MappingWrapper_SequenceMethods = {
0, // sq_length
0, // sq_concat
0, // sq_repeat
0, // sq_item
0, // sq_slice
0, // sq_ass_item
0, // sq_ass_slice
Dtool_MappingWrapper_contains,
0, // sq_inplace_concat
0, // sq_inplace_repeat
};
static PyMappingMethods Dtool_MappingWrapper_MappingMethods = {
0, // mp_length
Dtool_MappingWrapper_getitem,
Dtool_MappingWrapper_setitem,
};
static PyMethodDef Dtool_MappingWrapper_Methods[] = {
{"get", &Dtool_MappingWrapper_get, METH_VARARGS, nullptr},
{"pop", &Dtool_MappingWrapper_pop, METH_VARARGS, nullptr},
{"setdefault", &Dtool_MappingWrapper_setdefault, METH_VARARGS, nullptr},
{"update", (PyCFunction) &Dtool_MappingWrapper_update, METH_VARARGS | METH_KEYWORDS, nullptr},
{nullptr, nullptr, 0, nullptr}
};
PyTypeObject Dtool_MappingWrapper_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"mapping wrapper",
sizeof(Dtool_MappingWrapper),
0, // tp_itemsize
Dtool_WrapperBase_dealloc,
0, // tp_print
0, // tp_getattr
0, // tp_setattr
#if PY_MAJOR_VERSION >= 3
0, // tp_reserved
#else
0, // tp_compare
#endif
Dtool_WrapperBase_repr,
0, // tp_as_number
&Dtool_MappingWrapper_SequenceMethods,
&Dtool_MappingWrapper_MappingMethods,
0, // tp_hash
0, // tp_call
0, // tp_str
PyObject_GenericGetAttr,
PyObject_GenericSetAttr,
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
Dtool_MappingWrapper_Methods,
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
PyType_GenericAlloc,
0, // tp_new
PyObject_Del,
0, // tp_is_gc
0, // tp_bases
0, // tp_mro
0, // tp_cache
0, // tp_subclasses
0, // tp_weaklist
0, // tp_del
#if PY_VERSION_HEX >= 0x02060000
0, // tp_version_tag
#endif
#if PY_VERSION_HEX >= 0x03040000
0, // tp_finalize
#endif
};
/**
* This variant defines both a sequence and mapping interface.
*/
static PyMappingMethods Dtool_SeqMapWrapper_MappingMethods = {
Dtool_SeqMapWrapper_length,
Dtool_MappingWrapper_getitem,
Dtool_MappingWrapper_setitem,
};
static PyMethodDef Dtool_SeqMapWrapper_Methods[] = {
{"get", &Dtool_MappingWrapper_get, METH_VARARGS, nullptr},
{"pop", &Dtool_MappingWrapper_pop, METH_VARARGS, nullptr},
{"setdefault", &Dtool_MappingWrapper_setdefault, METH_VARARGS, nullptr},
{"update", (PyCFunction) &Dtool_MappingWrapper_update, METH_VARARGS | METH_KEYWORDS, nullptr},
{"values", &Dtool_SeqMapWrapper_values, METH_NOARGS, nullptr},
{nullptr, nullptr, 0, nullptr}
};
PyTypeObject Dtool_SeqMapWrapper_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"sequence/mapping wrapper",
sizeof(Dtool_SeqMapWrapper),
0, // tp_itemsize
Dtool_WrapperBase_dealloc,
0, // tp_print
0, // tp_getattr
0, // tp_setattr
#if PY_MAJOR_VERSION >= 3
0, // tp_reserved
#else
0, // tp_compare
#endif
Dtool_WrapperBase_repr,
0, // tp_as_number
0, // tp_as_sequence
&Dtool_MappingWrapper_MappingMethods,
0, // tp_hash
0, // tp_call
0, // tp_str
PyObject_GenericGetAttr,
PyObject_GenericSetAttr,
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
Dtool_SeqMapWrapper_Methods,
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
PyType_GenericAlloc,
0, // tp_new
PyObject_Del,
0, // tp_is_gc
0, // tp_bases
0, // tp_mro
0, // tp_cache
0, // tp_subclasses
0, // tp_weaklist
0, // tp_del
#if PY_VERSION_HEX >= 0x02060000
0, // tp_version_tag
#endif
#if PY_VERSION_HEX >= 0x03040000
0, // tp_finalize
#endif
};
/**
* This variant defines only a generator interface.
*/
static PyObject *Dtool_GeneratorWrapper_iternext(PyObject *self) {
Dtool_GeneratorWrapper *wrap = (Dtool_GeneratorWrapper *)self;
nassertr(wrap, nullptr);
nassertr(wrap->_iternext_func, nullptr);
return wrap->_iternext_func(wrap->_base._self);
}
PyTypeObject Dtool_GeneratorWrapper_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"generator wrapper",
sizeof(Dtool_GeneratorWrapper),
0, // tp_itemsize
Dtool_WrapperBase_dealloc,
0, // tp_print
0, // tp_getattr
0, // tp_setattr
#if PY_MAJOR_VERSION >= 3
0, // tp_reserved
#else
0, // tp_compare
#endif
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
PyObject_GenericGetAttr,
PyObject_GenericSetAttr,
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
PyObject_SelfIter,
Dtool_GeneratorWrapper_iternext,
0, // tp_methods
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
PyType_GenericAlloc,
0, // tp_new
PyObject_Del,
0, // tp_is_gc
0, // tp_bases
0, // tp_mro
0, // tp_cache
0, // tp_subclasses
0, // tp_weaklist
0, // tp_del
#if PY_VERSION_HEX >= 0x02060000
0, // tp_version_tag
#endif
#if PY_VERSION_HEX >= 0x03040000
0, // tp_finalize
#endif
};
/**
* This is a variant of the Python getset mechanism that permits static
* properties.
*/
PyObject *
Dtool_NewStaticProperty(PyTypeObject *type, const PyGetSetDef *getset) {
PyGetSetDescrObject *descr;
descr = (PyGetSetDescrObject *)PyType_GenericAlloc(&Dtool_StaticProperty_Type, 0);
if (descr != nullptr) {
Py_XINCREF(type);
descr->d_getset = (PyGetSetDef *)getset;
#if PY_MAJOR_VERSION >= 3
descr->d_common.d_type = type;
descr->d_common.d_name = PyUnicode_InternFromString(getset->name);
#if PY_VERSION_HEX >= 0x03030000
descr->d_common.d_qualname = nullptr;
#endif
#else
descr->d_type = type;
descr->d_name = PyString_InternFromString(getset->name);
#endif
}
return (PyObject *)descr;
}
static void
Dtool_StaticProperty_dealloc(PyDescrObject *descr) {
_PyObject_GC_UNTRACK(descr);
Py_XDECREF(descr->d_type);
Py_XDECREF(descr->d_name);
//#if PY_MAJOR_VERSION >= 3
// Py_XDECREF(descr->d_qualname);
//#endif
PyObject_GC_Del(descr);
}
static PyObject *
Dtool_StaticProperty_repr(PyDescrObject *descr, const char *format) {
#if PY_MAJOR_VERSION >= 3
return PyUnicode_FromFormat("<attribute '%s' of '%s'>",
PyUnicode_AsUTF8(descr->d_name),
descr->d_type->tp_name);
#else
return PyString_FromFormat("<attribute '%s' of '%s'>",
PyString_AS_STRING(descr->d_name),
descr->d_type->tp_name);
#endif
}
static int
Dtool_StaticProperty_traverse(PyObject *self, visitproc visit, void *arg) {
PyDescrObject *descr = (PyDescrObject *)self;
Py_VISIT(descr->d_type);
return 0;
}
static PyObject *
Dtool_StaticProperty_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) {
if (descr->d_getset->get != nullptr) {
return descr->d_getset->get(obj, descr->d_getset->closure);
} else {
return PyErr_Format(PyExc_AttributeError,
"attribute '%s' of type '%.100s' is not readable",
#if PY_MAJOR_VERSION >= 3
PyUnicode_AsUTF8(((PyDescrObject *)descr)->d_name),
#else
PyString_AS_STRING(((PyDescrObject *)descr)->d_name),
#endif
((PyDescrObject *)descr)->d_type->tp_name);
}
}
static int
Dtool_StaticProperty_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) {
if (descr->d_getset->set != nullptr) {
return descr->d_getset->set(obj, value, descr->d_getset->closure);
} else {
PyErr_Format(PyExc_AttributeError,
"attribute '%s' of type '%.100s' is not writable",
#if PY_MAJOR_VERSION >= 3
PyUnicode_AsUTF8(((PyDescrObject *)descr)->d_name),
#else
PyString_AS_STRING(((PyDescrObject *)descr)->d_name),
#endif
((PyDescrObject *)descr)->d_type->tp_name);
return -1;
}
}
PyTypeObject Dtool_StaticProperty_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"getset_descriptor",
sizeof(PyGetSetDescrObject),
0, // tp_itemsize
(destructor)Dtool_StaticProperty_dealloc,
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_reserved
(reprfunc)Dtool_StaticProperty_repr,
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
PyObject_GenericGetAttr,
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT,
0, // tp_doc
Dtool_StaticProperty_traverse,
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
(descrgetfunc)Dtool_StaticProperty_get,
(descrsetfunc)Dtool_StaticProperty_set,
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_del
0, // tp_is_gc
0, // tp_bases
0, // tp_mro
0, // tp_cache
0, // tp_subclasses
0, // tp_weaklist
0, // tp_del
#if PY_VERSION_HEX >= 0x02060000
0, // tp_version_tag
#endif
#if PY_VERSION_HEX >= 0x03040000
0, // tp_finalize
#endif
};
#endif // HAVE_PYTHON

View File

@ -468,49 +468,6 @@ copy_from_copy_constructor(PyObject *self, PyObject *noargs);
EXPCL_INTERROGATEDB PyObject *
map_deepcopy_to_copy(PyObject *self, PyObject *args);
/**
* These classes are returned from properties that require a subscript
* interface, ie. something.children[i] = 3.
*/
struct Dtool_WrapperBase {
PyObject_HEAD;
PyObject *_self;
const char *_name;
};
struct Dtool_SequenceWrapper {
Dtool_WrapperBase _base;
lenfunc _len_func;
ssizeargfunc _getitem_func;
ssizeobjargproc _setitem_func;
};
struct Dtool_MappingWrapper {
Dtool_WrapperBase _base;
binaryfunc _getitem_func;
objobjargproc _setitem_func;
};
struct Dtool_SeqMapWrapper {
Dtool_MappingWrapper _map;
lenfunc _len_func;
ssizeargfunc _seq_getitem_func;
ssizeobjargproc _seq_setitem_func;
};
struct Dtool_GeneratorWrapper {
Dtool_WrapperBase _base;
iternextfunc _iternext_func;
};
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SeqMapWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_GeneratorWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_StaticProperty_Type;
EXPCL_INTERROGATEDB PyObject *Dtool_NewStaticProperty(PyTypeObject *obj, const PyGetSetDef *getset);
/**
* These functions check whether the arguments passed to a function conform to
* certain expectations.
@ -566,6 +523,8 @@ EXPCL_INTERROGATEDB extern void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObjec
#include "py_panda.I"
#include "py_wrappers.h"
#endif // HAVE_PYTHON && !CPPPARSER
#endif // PY_PANDA_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file py_wrappers.h
* @author rdb
* @date 2017-11-26
*/
#ifndef PY_WRAPPERS_H
#define PY_WRAPPERS_H
#include "py_panda.h"
/**
* These classes are returned from properties that require a subscript
* interface, ie. something.children[i] = 3.
*/
struct Dtool_WrapperBase {
PyObject_HEAD;
PyObject *_self;
const char *_name;
};
struct Dtool_SequenceWrapper {
Dtool_WrapperBase _base;
lenfunc _len_func;
ssizeargfunc _getitem_func;
};
struct Dtool_MutableSequenceWrapper {
Dtool_WrapperBase _base;
lenfunc _len_func;
ssizeargfunc _getitem_func;
ssizeobjargproc _setitem_func;
PyObject *(*_insert_func)(PyObject *, size_t, PyObject *);
};
struct Dtool_MappingWrapper {
union {
Dtool_WrapperBase _base;
Dtool_SequenceWrapper _keys;
};
binaryfunc _getitem_func;
objobjargproc _setitem_func;
};
struct Dtool_GeneratorWrapper {
Dtool_WrapperBase _base;
iternextfunc _iternext_func;
};
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MutableSequenceWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MutableMappingWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Items_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Keys_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Values_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_GeneratorWrapper_Type;
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_StaticProperty_Type;
EXPCL_INTERROGATEDB Dtool_SequenceWrapper *Dtool_NewSequenceWrapper(PyObject *self, const char *name);
EXPCL_INTERROGATEDB Dtool_MutableSequenceWrapper *Dtool_NewMutableSequenceWrapper(PyObject *self, const char *name);
EXPCL_INTERROGATEDB Dtool_MappingWrapper *Dtool_NewMappingWrapper(PyObject *self, const char *name);
EXPCL_INTERROGATEDB Dtool_MappingWrapper *Dtool_NewMutableMappingWrapper(PyObject *self, const char *name);
EXPCL_INTERROGATEDB PyObject *Dtool_NewGenerator(PyObject *self, const char *name, iternextfunc func);
EXPCL_INTERROGATEDB PyObject *Dtool_NewStaticProperty(PyTypeObject *obj, const PyGetSetDef *getset);
#endif

View File

@ -66,6 +66,7 @@ extern "C" {
EXPCL_PYSTUB int PyInt_FromLong(...);
EXPCL_PYSTUB int PyInt_FromSize_t(...);
EXPCL_PYSTUB int PyInt_Type(...);
EXPCL_PYSTUB int PyIter_Next(...);
EXPCL_PYSTUB int PyList_Append(...);
EXPCL_PYSTUB int PyList_AsTuple(...);
EXPCL_PYSTUB int PyList_GetItem(...);
@ -91,6 +92,7 @@ extern "C" {
EXPCL_PYSTUB int PyModule_AddStringConstant(...);
EXPCL_PYSTUB int PyModule_Create2(...);
EXPCL_PYSTUB int PyModule_Create2TraceRefs(...);
EXPCL_PYSTUB int PyModule_GetDict(...);
EXPCL_PYSTUB int PyNumber_AsSsize_t(...);
EXPCL_PYSTUB int PyNumber_Check(...);
EXPCL_PYSTUB int PyNumber_Float(...);
@ -111,15 +113,18 @@ extern "C" {
EXPCL_PYSTUB int PyObject_GenericSetAttr(...);
EXPCL_PYSTUB int PyObject_GetAttrString(...);
EXPCL_PYSTUB int PyObject_GetBuffer(...);
EXPCL_PYSTUB int PyObject_GetIter(...);
EXPCL_PYSTUB int PyObject_HasAttrString(...);
EXPCL_PYSTUB int PyObject_IsInstance(...);
EXPCL_PYSTUB int PyObject_IsTrue(...);
EXPCL_PYSTUB int PyObject_Malloc(...);
EXPCL_PYSTUB int PyObject_Repr(...);
EXPCL_PYSTUB int PyObject_RichCompareBool(...);
EXPCL_PYSTUB int PyObject_SelfIter(...);
EXPCL_PYSTUB int PyObject_SetAttrString(...);
EXPCL_PYSTUB int PyObject_Str(...);
EXPCL_PYSTUB int PyObject_Type(...);
EXPCL_PYSTUB int PySeqIter_New(...);
EXPCL_PYSTUB int PySequence_Check(...);
EXPCL_PYSTUB int PySequence_Fast(...);
EXPCL_PYSTUB int PySequence_GetItem(...);
@ -290,6 +295,7 @@ int PyInt_AsSsize_t(...) { return 0; }
int PyInt_FromLong(...) { return 0; }
int PyInt_FromSize_t(...) { return 0; }
int PyInt_Type(...) { return 0; }
int PyIter_Next(...) { return 0; }
int PyList_Append(...) { return 0; }
int PyList_AsTuple(...) { return 0; }
int PyList_GetItem(...) { return 0; }
@ -315,6 +321,7 @@ int PyModule_AddObject(...) { return 0; };
int PyModule_AddStringConstant(...) { return 0; };
int PyModule_Create2(...) { return 0; };
int PyModule_Create2TraceRefs(...) { return 0; };
int PyModule_GetDict(...) { return 0; };
int PyNumber_AsSsize_t(...) { return 0; }
int PyNumber_Check(...) { return 0; }
int PyNumber_Float(...) { return 0; }
@ -335,15 +342,18 @@ int PyObject_GenericGetAttr(...) { return 0; };
int PyObject_GenericSetAttr(...) { return 0; };
int PyObject_GetAttrString(...) { return 0; }
int PyObject_GetBuffer(...) { return 0; }
int PyObject_GetIter(...) { return 0; }
int PyObject_HasAttrString(...) { return 0; }
int PyObject_IsInstance(...) { return 0; }
int PyObject_IsTrue(...) { return 0; }
int PyObject_Malloc(...) { return 0; }
int PyObject_Repr(...) { return 0; }
int PyObject_RichCompareBool(...) { return 0; }
int PyObject_SelfIter(...) { return 0; }
int PyObject_SetAttrString(...) { return 0; }
int PyObject_Str(...) { return 0; }
int PyObject_Type(...) { return 0; }
int PySeqIter_New(...) { return 0; }
int PySequence_Check(...) { return 0; }
int PySequence_Fast(...) { return 0; }
int PySequence_GetItem(...) { return 0; }

View File

@ -768,9 +768,11 @@ if (COMPILER == "MSVC"):
DefSymbol("WX", "_UNICODE", "")
DefSymbol("WX", "UNICODE", "")
if (PkgSkip("VORBIS")==0):
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libogg_static.lib")
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libvorbis_static.lib")
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libvorbisfile_static.lib")
for lib in ('ogg', 'vorbis', 'vorbisfile'):
path = GetThirdpartyDir() + "vorbis/lib/lib{0}_static.lib".format(lib)
if not os.path.isfile(path):
path = GetThirdpartyDir() + "vorbis/lib/{0}.lib".format(lib)
LibName("VORBIS", path)
if (PkgSkip("OPUS")==0):
LibName("OPUS", GetThirdpartyDir() + "opus/lib/libogg_static.lib")
LibName("OPUS", GetThirdpartyDir() + "opus/lib/libopus_static.lib")

View File

@ -49,7 +49,6 @@ PUBLISHED:
void sort_descendants();
MAKE_SEQ_PROPERTY(children, get_num_children, get_child);
MAKE_MAP_PROPERTY(children, get_child_named, get_child_named);
public:
virtual TypeHandle get_value_type() const;

View File

@ -76,7 +76,6 @@ PUBLISHED:
void sort_descendants();
MAKE_SEQ_PROPERTY(children, get_num_children, get_child);
MAKE_MAP_PROPERTY(children, get_child_named, get_child_named);
bool apply_freeze(const TransformState *transform);
virtual bool apply_freeze_matrix(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale);

View File

@ -65,7 +65,7 @@ clear_solids() {
/**
*
*/
INLINE int CollisionNode::
INLINE size_t CollisionNode::
get_num_solids() const {
return _solids.size();
}
@ -74,8 +74,8 @@ get_num_solids() const {
*
*/
INLINE CPT(CollisionSolid) CollisionNode::
get_solid(int n) const {
nassertr(n >= 0 && n < get_num_solids(), NULL);
get_solid(size_t n) const {
nassertr(n < get_num_solids(), nullptr);
return _solids[n].get_read_pointer();
}
@ -83,8 +83,8 @@ get_solid(int n) const {
*
*/
INLINE PT(CollisionSolid) CollisionNode::
modify_solid(int n) {
nassertr(n >= 0 && n < get_num_solids(), NULL);
modify_solid(size_t n) {
nassertr(n < get_num_solids(), nullptr);
mark_internal_bounds_stale();
return _solids[n].get_write_pointer();
}
@ -93,19 +93,31 @@ modify_solid(int n) {
* Replaces the solid with the indicated index.
*/
INLINE void CollisionNode::
set_solid(int n, CollisionSolid *solid) {
nassertv(n >= 0 && n < get_num_solids());
set_solid(size_t n, CollisionSolid *solid) {
nassertv(n < get_num_solids());
_solids[n] = solid;
mark_internal_bounds_stale();
}
/**
* Inserts the indicated solid to the node at the indicated position.
*/
INLINE void CollisionNode::
insert_solid(size_t n, const CollisionSolid *solid) {
if (n > _solids.size()) {
n = _solids.size();
}
_solids.insert(_solids.begin() + n, (CollisionSolid *)solid);
mark_internal_bounds_stale();
}
/**
* Removes the solid with the indicated index. This will shift all subsequent
* indices down by one.
*/
INLINE void CollisionNode::
remove_solid(int n) {
nassertv(n >= 0 && n < get_num_solids());
remove_solid(size_t n) {
nassertv(n < get_num_solids());
_solids.erase(_solids.begin() + n);
mark_internal_bounds_stale();
}
@ -114,7 +126,7 @@ remove_solid(int n) {
* Adds the indicated solid to the node. Returns the index of the new solid
* within the node's list of solids.
*/
INLINE int CollisionNode::
INLINE size_t CollisionNode::
add_solid(const CollisionSolid *solid) {
_solids.push_back((CollisionSolid *)solid);
mark_internal_bounds_stale();

View File

@ -61,14 +61,15 @@ PUBLISHED:
set_into_collide_mask);
INLINE void clear_solids();
INLINE int get_num_solids() const;
INLINE CPT(CollisionSolid) get_solid(int n) const;
INLINE size_t get_num_solids() const;
INLINE CPT(CollisionSolid) get_solid(size_t n) const;
MAKE_SEQ(get_solids, get_num_solids, get_solid);
INLINE PT(CollisionSolid) modify_solid(int n);
INLINE void set_solid(int n, CollisionSolid *solid);
INLINE void remove_solid(int n);
INLINE int add_solid(const CollisionSolid *solid);
MAKE_SEQ_PROPERTY(solids, get_num_solids, get_solid, set_solid, remove_solid);
INLINE PT(CollisionSolid) modify_solid(size_t n);
INLINE void set_solid(size_t n, CollisionSolid *solid);
INLINE void insert_solid(size_t n, const CollisionSolid *solid);
INLINE void remove_solid(size_t n);
INLINE size_t add_solid(const CollisionSolid *solid);
MAKE_SEQ_PROPERTY(solids, get_num_solids, get_solid, set_solid, remove_solid, insert_solid);
INLINE int get_collider_sort() const;
INLINE void set_collider_sort(int sort);

View File

@ -584,8 +584,7 @@ get_quality(const FrameBufferProperties &reqs) const {
// However, deduct for color bits above 24, if we are requesting only 1.
// This is to prevent choosing a 64-bit color mode in NVIDIA cards that
// is linear and therefore causes the gamma to be off in non-sRGB pipelines.
if ((reqs._property[FBP_color_bits] == 1 || reqs._property[FBP_color_bits] == 3) &&
_property[FBP_color_bits] > 24) {
if (reqs._property[FBP_color_bits] <= 3 && _property[FBP_color_bits] > 24) {
quality -= 100;
}

View File

@ -38,7 +38,7 @@ operator = (const EggCompositePrimitive &copy) {
* Returns the number of individual component triangles within the composite.
* Each one of these might have a different set of attributes.
*/
INLINE int EggCompositePrimitive::
INLINE size_t EggCompositePrimitive::
get_num_components() const {
return _components.size();
}
@ -47,8 +47,8 @@ get_num_components() const {
* Returns the attributes for the nth component triangle.
*/
INLINE const EggAttributes *EggCompositePrimitive::
get_component(int i) const {
nassertr(i >= 0 && i < (int)_components.size(), NULL);
get_component(size_t i) const {
nassertr(i < _components.size(), nullptr);
return _components[i];
}
@ -56,8 +56,8 @@ get_component(int i) const {
* Returns the attributes for the nth component triangle.
*/
INLINE EggAttributes *EggCompositePrimitive::
get_component(int i) {
nassertr(i >= 0 && i < (int)_components.size(), NULL);
get_component(size_t i) {
nassertr(i < _components.size(), nullptr);
return _components[i];
}
@ -65,8 +65,8 @@ get_component(int i) {
* Changes the attributes for the nth component triangle.
*/
INLINE void EggCompositePrimitive::
set_component(int i, const EggAttributes *attrib) {
nassertv(i >= 0 && i < (int)_components.size());
set_component(size_t i, const EggAttributes *attrib) {
nassertv(i < _components.size());
_components[i] = new EggAttributes(*attrib);
}

View File

@ -32,11 +32,11 @@ PUBLISHED:
virtual Shading get_shading() const;
INLINE int get_num_components() const;
INLINE const EggAttributes *get_component(int i) const;
INLINE EggAttributes *get_component(int i);
INLINE size_t get_num_components() const;
INLINE const EggAttributes *get_component(size_t i) const;
INLINE EggAttributes *get_component(size_t i);
MAKE_SEQ(get_components, get_num_components, get_component);
INLINE void set_component(int i, const EggAttributes *attrib);
INLINE void set_component(size_t i, const EggAttributes *attrib);
MAKE_SEQ_PROPERTY(components, get_num_components, get_component, set_component);

View File

@ -372,6 +372,17 @@ set_vertex(size_t index, EggVertex *vertex) {
replace(begin() + index, vertex);
}
/**
* Inserts a vertex at the given position.
*/
INLINE void EggPrimitive::
insert_vertex(size_t index, EggVertex *vertex) {
if (index > _vertices.size()) {
index = _vertices.size();
}
_vertices.insert(_vertices.begin() + index, vertex);
}
/**
* Returns a particular index based on its index number.
*/
@ -381,7 +392,6 @@ get_vertex(size_t index) const {
return *(begin() + index);
}
/**
* Returns the vertex pool associated with the vertices of the primitive, or
* NULL if the primitive has no vertices.

View File

@ -181,13 +181,14 @@ PUBLISHED:
// These are shorthands if you don't want to use the iterators.
INLINE size_t get_num_vertices() const;
INLINE void set_vertex(size_t index, EggVertex *vertex);
INLINE EggVertex *get_vertex(size_t index) const;
INLINE void set_vertex(size_t index, EggVertex *vertex);
INLINE void insert_vertex(size_t index, EggVertex *vertex);
MAKE_SEQ(get_vertices, get_num_vertices, get_vertex);
INLINE EggVertexPool *get_pool() const;
MAKE_SEQ_PROPERTY(vertices, get_num_vertices, get_vertex, set_vertex, remove_vertex);
MAKE_SEQ_PROPERTY(vertices, get_num_vertices, get_vertex, set_vertex, remove_vertex, insert_vertex);
MAKE_PROPERTY(pool, get_pool);
virtual void write(ostream &out, int indent_level) const=0;

View File

@ -68,7 +68,7 @@ is_empty() const {
* Returns the number of GeomPrimitive objects stored within the Geom, each of
* which represents a number of primitives of a particular type.
*/
INLINE int Geom::
INLINE size_t Geom::
get_num_primitives() const {
CDReader cdata(_cycler);
return cdata->_primitives.size();
@ -80,9 +80,9 @@ get_num_primitives() const {
* or set_primitive() if you want to modify it.
*/
INLINE CPT(GeomPrimitive) Geom::
get_primitive(int i) const {
get_primitive(size_t i) const {
CDReader cdata(_cycler);
nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL);
nassertr(i < cdata->_primitives.size(), nullptr);
return cdata->_primitives[i].get_read_pointer();
}
@ -95,15 +95,28 @@ get_primitive(int i) const {
* away other changes you might have recently made in an upstream thread.
*/
INLINE PT(GeomPrimitive) Geom::
modify_primitive(int i) {
modify_primitive(size_t i) {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL);
nassertr(i < cdata->_primitives.size(), NULL);
cdata->_modified = Geom::get_next_modified();
clear_cache_stage(current_thread);
return cdata->_primitives[i].get_write_pointer();
}
/**
* Inserts a new GeomPrimitive structure to the Geom object. This specifies a
* particular subset of vertices that are used to define geometric primitives
* of the indicated type.
*
* Don't call this in a downstream thread unless you don't mind it blowing
* away other changes you might have recently made in an upstream thread.
*/
INLINE void Geom::
add_primitive(const GeomPrimitive *primitive) {
insert_primitive((size_t)-1, primitive);
}
/**
* Decomposes all of the primitives within this Geom, returning the result.
* See GeomPrimitive::decompose().

View File

@ -294,10 +294,10 @@ make_nonindexed(bool composite_only) {
* away other changes you might have recently made in an upstream thread.
*/
void Geom::
set_primitive(int i, const GeomPrimitive *primitive) {
set_primitive(size_t i, const GeomPrimitive *primitive) {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
nassertv(i >= 0 && i < (int)cdata->_primitives.size());
nassertv(i < cdata->_primitives.size());
nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
// All primitives within a particular Geom must have the same fundamental
@ -327,7 +327,7 @@ set_primitive(int i, const GeomPrimitive *primitive) {
}
/**
* Adds a new GeomPrimitive structure to the Geom object. This specifies a
* Inserts a new GeomPrimitive structure to the Geom object. This specifies a
* particular subset of vertices that are used to define geometric primitives
* of the indicated type.
*
@ -335,7 +335,7 @@ set_primitive(int i, const GeomPrimitive *primitive) {
* away other changes you might have recently made in an upstream thread.
*/
void Geom::
add_primitive(const GeomPrimitive *primitive) {
insert_primitive(size_t i, const GeomPrimitive *primitive) {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
@ -348,9 +348,13 @@ add_primitive(const GeomPrimitive *primitive) {
// They also should have a compatible shade model.
CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model);
nassertv_always(compat != (GeomPrimitive *)NULL);
nassertv_always(compat != nullptr);
cdata->_primitives.push_back((GeomPrimitive *)compat.p());
if (i >= cdata->_primitives.size()) {
cdata->_primitives.push_back((GeomPrimitive *)compat.p());
} else {
cdata->_primitives.insert(cdata->_primitives.begin() + i, (GeomPrimitive *)compat.p());
}
PrimitiveType new_primitive_type = compat->get_primitive_type();
if (new_primitive_type != cdata->_primitive_type) {
cdata->_primitive_type = new_primitive_type;
@ -374,10 +378,10 @@ add_primitive(const GeomPrimitive *primitive) {
* away other changes you might have recently made in an upstream thread.
*/
void Geom::
remove_primitive(int i) {
remove_primitive(size_t i) {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
nassertv(i >= 0 && i < (int)cdata->_primitives.size());
nassertv(i < cdata->_primitives.size());
cdata->_primitives.erase(cdata->_primitives.begin() + i);
if (cdata->_primitives.empty()) {
cdata->_primitive_type = PT_none;

View File

@ -87,15 +87,16 @@ PUBLISHED:
INLINE bool is_empty() const;
INLINE int get_num_primitives() const;
INLINE CPT(GeomPrimitive) get_primitive(int i) const;
INLINE size_t get_num_primitives() const;
INLINE CPT(GeomPrimitive) get_primitive(size_t i) const;
MAKE_SEQ(get_primitives, get_num_primitives, get_primitive);
INLINE PT(GeomPrimitive) modify_primitive(int i);
void set_primitive(int i, const GeomPrimitive *primitive);
void add_primitive(const GeomPrimitive *primitive);
void remove_primitive(int i);
INLINE PT(GeomPrimitive) modify_primitive(size_t i);
void set_primitive(size_t i, const GeomPrimitive *primitive);
void insert_primitive(size_t i, const GeomPrimitive *primitive);
INLINE void add_primitive(const GeomPrimitive *primitive);
void remove_primitive(size_t i);
void clear_primitives();
MAKE_SEQ_PROPERTY(primitives, get_num_primitives, get_primitive, set_primitive, remove_primitive);
MAKE_SEQ_PROPERTY(primitives, get_num_primitives, get_primitive, set_primitive, remove_primitive, insert_primitive);
INLINE PT(Geom) decompose() const;
INLINE PT(Geom) doubleside() const;

View File

@ -129,7 +129,7 @@ reserve_num_rows(int n) {
* Returns the number of individual arrays stored within the data. This must
* match get_format()->get_num_arrays().
*/
INLINE int GeomVertexData::
INLINE size_t GeomVertexData::
get_num_arrays() const {
CDReader cdata(_cycler);
return cdata->_arrays.size();
@ -141,9 +141,9 @@ get_num_arrays() const {
* data.
*/
INLINE CPT(GeomVertexArrayData) GeomVertexData::
get_array(int i) const {
get_array(size_t i) const {
CDReader cdata(_cycler);
nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
nassertr(i < cdata->_arrays.size(), nullptr);
return cdata->_arrays[i].get_read_pointer();
}
@ -151,10 +151,10 @@ get_array(int i) const {
* Equivalent to get_array(i).get_handle().
*/
INLINE CPT(GeomVertexArrayDataHandle) GeomVertexData::
get_array_handle(int i) const {
get_array_handle(size_t i) const {
Thread *current_thread = Thread::get_current_thread();
CDReader cdata(_cycler, current_thread);
nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
nassertr(i < cdata->_arrays.size(), nullptr);
return new GeomVertexArrayDataHandle(cdata->_arrays[i].get_read_pointer(), current_thread);
}
@ -168,7 +168,7 @@ get_array_handle(int i) const {
* away other changes you might have recently made in an upstream thread.
*/
INLINE PT(GeomVertexArrayData) GeomVertexData::
modify_array(int i) {
modify_array(size_t i) {
GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread());
return writer.modify_array(i);
}
@ -177,7 +177,7 @@ modify_array(int i) {
* Equivalent to modify_array(i).modify_handle().
*/
INLINE PT(GeomVertexArrayDataHandle) GeomVertexData::
modify_array_handle(int i) {
modify_array_handle(size_t i) {
Thread *current_thread = Thread::get_current_thread();
GeomVertexDataPipelineWriter writer(this, true, current_thread);
return new GeomVertexArrayDataHandle(writer.modify_array(i), current_thread);
@ -192,7 +192,7 @@ modify_array_handle(int i) {
* away other changes you might have recently made in an upstream thread.
*/
INLINE void GeomVertexData::
set_array(int i, const GeomVertexArrayData *array) {
set_array(size_t i, const GeomVertexArrayData *array) {
GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread());
writer.set_array(i, array);
}
@ -888,9 +888,9 @@ check_array_writers() const {
*
*/
INLINE GeomVertexArrayDataHandle *GeomVertexDataPipelineWriter::
get_array_writer(int i) const {
get_array_writer(size_t i) const {
nassertr(_got_array_writers, NULL);
nassertr(i >= 0 && i < (int)_array_writers.size(), NULL);
nassertr(i < _array_writers.size(), nullptr);
return _array_writers[i];
}

View File

@ -2565,8 +2565,8 @@ reserve_num_rows(int n) {
*
*/
PT(GeomVertexArrayData) GeomVertexDataPipelineWriter::
modify_array(int i) {
nassertr(i >= 0 && i < (int)_cdata->_arrays.size(), NULL);
modify_array(size_t i) {
nassertr(i < _cdata->_arrays.size(), nullptr);
PT(GeomVertexArrayData) new_data;
if (_got_array_writers) {
@ -2586,8 +2586,8 @@ modify_array(int i) {
*
*/
void GeomVertexDataPipelineWriter::
set_array(int i, const GeomVertexArrayData *array) {
nassertv(i >= 0 && i < (int)_cdata->_arrays.size());
set_array(size_t i, const GeomVertexArrayData *array) {
nassertv(i < _cdata->_arrays.size());
_cdata->_arrays[i] = (GeomVertexArrayData *)array;
_object->clear_cache_stage();
_cdata->_modified = Geom::get_next_modified();

View File

@ -105,13 +105,13 @@ PUBLISHED:
INLINE bool reserve_num_rows(int n);
void clear_rows();
INLINE int get_num_arrays() const;
INLINE CPT(GeomVertexArrayData) get_array(int i) const;
INLINE CPT(GeomVertexArrayDataHandle) get_array_handle(int i) const;
INLINE size_t get_num_arrays() const;
INLINE CPT(GeomVertexArrayData) get_array(size_t i) const;
INLINE CPT(GeomVertexArrayDataHandle) get_array_handle(size_t i) const;
MAKE_SEQ(get_arrays, get_num_arrays, get_array);
INLINE PT(GeomVertexArrayData) modify_array(int i);
INLINE PT(GeomVertexArrayDataHandle) modify_array_handle(int i);
INLINE void set_array(int i, const GeomVertexArrayData *array);
INLINE PT(GeomVertexArrayData) modify_array(size_t i);
INLINE PT(GeomVertexArrayDataHandle) modify_array_handle(size_t i);
INLINE void set_array(size_t i, const GeomVertexArrayData *array);
MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array);
INLINE const TransformTable *get_transform_table() const;
@ -520,10 +520,10 @@ public:
INLINE GeomVertexData *get_object() const;
INLINE void check_array_writers() const;
INLINE GeomVertexArrayDataHandle *get_array_writer(int i) const;
INLINE GeomVertexArrayDataHandle *get_array_writer(size_t i) const;
PT(GeomVertexArrayData) modify_array(int i);
void set_array(int i, const GeomVertexArrayData *array);
PT(GeomVertexArrayData) modify_array(size_t i);
void set_array(size_t i, const GeomVertexArrayData *array);
int get_num_rows() const;
bool set_num_rows(int n);

View File

@ -310,7 +310,9 @@ add_array(const GeomVertexArrayFormat *array_format) {
void GeomVertexFormat::
insert_array(size_t array, const GeomVertexArrayFormat *array_format) {
nassertv(!is_registered());
nassertv(array <= _arrays.size());
if (array > _arrays.size()) {
array = _arrays.size();
}
_arrays.insert(_arrays.begin() + array, (GeomVertexArrayFormat *)array_format);
}
@ -377,6 +379,22 @@ get_column(size_t i) const {
return NULL;
}
/**
* Returns the name of the ith column, across all arrays.
*/
const InternalName *GeomVertexFormat::
get_column_name(size_t i) const {
Arrays::const_iterator ai;
for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
if (i < (size_t)(*ai)->get_num_columns()) {
return (*ai)->get_column(i)->get_name();
}
i -= (*ai)->get_num_columns();
}
return nullptr;
}
/**
* Returns the index number of the array with the ith column.
*

View File

@ -92,6 +92,7 @@ PUBLISHED:
int get_array_with(const InternalName *name) const;
const GeomVertexColumn *get_column(const InternalName *name) const;
INLINE bool has_column(const InternalName *name) const;
const InternalName *get_column_name(size_t i) const;
MAKE_SEQ(get_columns, get_num_columns, get_column);
@ -120,13 +121,13 @@ PUBLISHED:
MAKE_SEQ(get_morph_bases, get_num_morphs, get_morph_base);
MAKE_SEQ(get_morph_deltas, get_num_morphs, get_morph_delta);
MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array, remove_array);
MAKE_SEQ_PROPERTY(columns, get_num_columns, get_column);
MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array, remove_array, insert_array);
MAKE_SEQ_PROPERTY(points, get_num_points, get_point);
MAKE_SEQ_PROPERTY(vectors, get_num_vectors, get_vector);
// We also define this as a mapping interface, for lookups by name.
MAKE_MAP_PROPERTY(columns, has_column, get_column);
MAKE_MAP_KEYS_SEQ(columns, get_num_columns, get_column_name);
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;

View File

@ -68,8 +68,8 @@ PUBLISHED:
MAKE_SEQ_PROPERTY(transforms, get_num_transforms, get_transform,
set_transform, remove_transform);
MAKE_SEQ_PROPERTY(weights, get_num_transforms, get_weight, set_weight);
MAKE_MAP_PROPERTY(weights, has_transform, get_weight);
MAKE_MAP_KEYS_SEQ(weights, get_num_transforms, get_transform);
INLINE void update_blend(Thread *current_thread) const;

View File

@ -65,6 +65,23 @@ set_transform(size_t n, const VertexTransform *transform) {
_transforms[n] = transform;
}
/**
* Inserts a new transform to the table at the given index position. If the
* index is beyond the end of the table, appends it to the end. Only valid
* for unregistered tables.
*
* This does not automatically uniquify the pointer; if the transform is
* already present in the table, it will be added twice.
*/
void TransformTable::
insert_transform(size_t n, const VertexTransform *transform) {
nassertv(!_is_registered);
if (n > _transforms.size()) {
n = _transforms.size();
}
_transforms.insert(_transforms.begin() + n, transform);
}
/**
* Removes the nth transform. Only valid for unregistered tables.
*/

View File

@ -51,6 +51,7 @@ PUBLISHED:
INLINE UpdateSeq get_modified(Thread *current_thread = Thread::get_current_thread()) const;
void set_transform(size_t n, const VertexTransform *transform);
void insert_transform(size_t n, const VertexTransform *transform);
void remove_transform(size_t n);
size_t add_transform(const VertexTransform *transform);
@ -58,7 +59,8 @@ PUBLISHED:
MAKE_PROPERTY(registered, is_registered);
MAKE_PROPERTY(modified, get_modified);
MAKE_SEQ_PROPERTY(transforms, get_num_transforms, get_transform, set_transform, remove_transform);
MAKE_SEQ_PROPERTY(transforms, get_num_transforms, get_transform, set_transform,
remove_transform, insert_transform);
private:
void do_register();

View File

@ -36,6 +36,15 @@ get_curve(int index) const {
return _curves[index];
}
/**
* Adds a new ParametricCurve to the collection at the indicated index.
* @deprecated Use insert_curve(index, curve) instead.
*/
INLINE void ParametricCurveCollection::
add_curve(ParametricCurve *curve, int index) {
insert_curve(max(index, 0), curve);
}
/**
* Returns the maximum T value associated with the *last* curve in the
* collection. Normally, this will be either the XYZ or HPR curve, or a

View File

@ -42,9 +42,9 @@ add_curve(ParametricCurve *curve) {
* Adds a new ParametricCurve to the collection at the indicated index.
*/
void ParametricCurveCollection::
add_curve(ParametricCurve *curve, int index) {
insert_curve(size_t index, ParametricCurve *curve) {
prepare_add_curve(curve);
index = max(min(index, (int)_curves.size()), 0);
index = min(index, _curves.size());
_curves.insert(_curves.begin() + index, curve);
redraw();
}
@ -93,8 +93,8 @@ remove_curve(ParametricCurve *curve) {
* number.
*/
void ParametricCurveCollection::
remove_curve(int index) {
nassertv(index >= 0 && index < (int)_curves.size());
remove_curve(size_t index) {
nassertv(index < _curves.size());
PT(ParametricCurve) curve = _curves[index];
prepare_remove_curve(curve);
_curves.erase(_curves.begin() + index);
@ -107,8 +107,8 @@ remove_curve(int index) {
* number.
*/
void ParametricCurveCollection::
set_curve(int index, ParametricCurve *curve) {
nassertv(index >= 0 && index < (int)_curves.size());
set_curve(size_t index, ParametricCurve *curve) {
nassertv(index < _curves.size());
prepare_remove_curve(_curves[index]);
prepare_add_curve(curve);
_curves[index] = curve;

View File

@ -41,10 +41,11 @@ PUBLISHED:
void add_curve(ParametricCurve *curve);
void add_curve(ParametricCurve *curve, int index);
void insert_curve(size_t index, ParametricCurve *curve);
int add_curves(PandaNode *node);
bool remove_curve(ParametricCurve *curve);
void remove_curve(int index);
void set_curve(int index, ParametricCurve *curve);
void remove_curve(size_t index);
void set_curve(size_t index, ParametricCurve *curve);
bool has_curve(ParametricCurve *curve) const;
void clear();
void clear_timewarps();

View File

@ -913,10 +913,11 @@ PUBLISHED:
INLINE bool has_net_tag(const string &key) const;
NodePath find_net_tag(const string &key) const;
MAKE_MAP_PROPERTY(tags, has_tag, get_tag, set_tag, clear_tag);
MAKE_MAP_PROPERTY(net_tags, has_net_tag, get_net_tag);
EXTENSION(INLINE PyObject *get_tags() const);
EXTENSION(INLINE PyObject *get_tag_keys() const);
MAKE_PROPERTY(tags, get_tags);
EXTENSION(PyObject *get_python_tags());
EXTENSION(INLINE void set_python_tag(PyObject *keys, PyObject *value));

View File

@ -32,6 +32,7 @@ get_python_tags() {
/**
* This variant on get_tag_keys returns a Python list of strings. Returns
* None if the NodePath is empty.
* @deprecated use `np.tags.keys()` instead.
*/
INLINE PyObject *Extension<NodePath>::
get_tag_keys() const {

View File

@ -27,6 +27,7 @@ extern struct Dtool_PyTypedObject Dtool_LPoint3d;
extern struct Dtool_PyTypedObject Dtool_LPoint3f;
#endif
extern struct Dtool_PyTypedObject Dtool_NodePath;
extern struct Dtool_PyTypedObject Dtool_PandaNode;
#endif // CPPPARSER
/**
@ -130,7 +131,7 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
}
// Start by getting this class object.
PyObject *this_class = PyObject_Type(self);
PyObject *this_class = (PyObject *)Py_TYPE(self);
if (this_class == NULL) {
return NULL;
}
@ -143,7 +144,6 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
func = Extension<TypedWritable>::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream_persist");
if (func == NULL) {
PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream_persist()");
Py_DECREF(this_class);
return NULL;
}
@ -153,15 +153,13 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
func = Extension<TypedWritable>::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream");
if (func == NULL) {
PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream()");
Py_DECREF(this_class);
return NULL;
}
}
// PyTuple_SET_ITEM conveniently borrows the reference it is passed.
PyObject *args = PyTuple_New(2);
PyTuple_SET_ITEM(args, 0, this_class);
PyTuple_SET_ITEM(args, 1, Dtool_WrapValue(bam_stream));
PyObject *args = PyTuple_New(1);
PyTuple_SET_ITEM(args, 0, Dtool_WrapValue(bam_stream));
PyObject *tuple = PyTuple_New(2);
PyTuple_SET_ITEM(tuple, 0, func);
@ -169,6 +167,30 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
return tuple;
}
/**
* Returns the associated node's tags.
*/
PyObject *Extension<NodePath>::
get_tags() const {
// An empty NodePath returns None
if (_this->is_empty()) {
Py_INCREF(Py_None);
return Py_None;
}
// Just call PandaNode.tags rather than defining a whole new interface.
PT(PandaNode) node = _this->node();
PyObject *py_node = DTool_CreatePyInstanceTyped
((void *)node.p(), Dtool_PandaNode, true, false, node->get_type_index());
// DTool_CreatePyInstanceTyped() steals a C++ reference.
node.cheat() = nullptr;
PyObject *result = PyObject_GetAttrString(py_node, "tags");
Py_DECREF(py_node);
return result;
}
/**
* Returns the lowest ancestor of this node that contains a tag definition
* with the indicated key, if any, or an empty NodePath if no ancestor of this

View File

@ -34,6 +34,7 @@ public:
PyObject *__reduce__(PyObject *self) const;
PyObject *__reduce_persist__(PyObject *self, PyObject *pickler) const;
PyObject *get_tags() const;
INLINE PyObject *get_tag_keys() const;
INLINE PyObject *get_python_tags();

View File

@ -348,12 +348,12 @@ has_dirty_prev_transform() const {
INLINE string PandaNode::
get_tag(const string &key, Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
TagData::const_iterator ti;
ti = cdata->_tag_data.find(key);
if (ti != cdata->_tag_data.end()) {
return (*ti).second;
int index = cdata->_tag_data.find(key);
if (index >= 0) {
return cdata->_tag_data.get_data((size_t)index);
} else {
return string();
}
return string();
}
/**
@ -364,9 +364,25 @@ get_tag(const string &key, Thread *current_thread) const {
INLINE bool PandaNode::
has_tag(const string &key, Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
TagData::const_iterator ti;
ti = cdata->_tag_data.find(key);
return (ti != cdata->_tag_data.end());
return cdata->_tag_data.find(key) >= 0;
}
/**
* Returns the number of tags applied to this node.
*/
INLINE size_t PandaNode::
get_num_tags() const {
CDReader cdata(_cycler);
return cdata->_tag_data.size();
}
/**
* Returns the key of the nth tag applied to this node.
*/
INLINE string PandaNode::
get_tag_key(size_t i) const {
CDReader cdata(_cycler);
return cdata->_tag_data.get_key(i);
}
/**
@ -376,7 +392,7 @@ has_tag(const string &key, Thread *current_thread) const {
INLINE bool PandaNode::
has_tags() const {
CDReader cdata(_cycler);
if (!cdata->_tag_data.empty()) {
if (!cdata->_tag_data.is_empty()) {
return true;
}
#ifdef HAVE_PYTHON
@ -1448,12 +1464,12 @@ get_prev_transform() const {
*/
INLINE string PandaNodePipelineReader::
get_tag(const string &key) const {
PandaNode::TagData::const_iterator ti;
ti = _cdata->_tag_data.find(key);
if (ti != _cdata->_tag_data.end()) {
return (*ti).second;
int index = _cdata->_tag_data.find(key);
if (index >= 0) {
return _cdata->_tag_data.get_data((size_t)index);
} else {
return string();
}
return string();
}
/**
@ -1463,9 +1479,7 @@ get_tag(const string &key) const {
*/
INLINE bool PandaNodePipelineReader::
has_tag(const string &key) const {
PandaNode::TagData::const_iterator ti;
ti = _cdata->_tag_data.find(key);
return (ti != _cdata->_tag_data.end());
return _cdata->_tag_data.find(key) >= 0;
}
/**

View File

@ -1216,7 +1216,7 @@ set_tag(const string &key, const string &value, Thread *current_thread) {
// stages.
OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
cdata->_tag_data[key] = value;
cdata->_tag_data.store(key, value);
cdata->set_fancy_bit(FB_tag, true);
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
@ -1231,8 +1231,8 @@ void PandaNode::
clear_tag(const string &key, Thread *current_thread) {
OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
cdata->_tag_data.erase(key);
cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.empty());
cdata->_tag_data.remove(key);
cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.is_empty());
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
mark_bam_modified();
@ -1257,13 +1257,10 @@ copy_tags(PandaNode *other) {
CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
TagData::const_iterator ti;
for (ti = cdatar->_tag_data.begin();
ti != cdatar->_tag_data.end();
++ti) {
cdataw->_tag_data[(*ti).first] = (*ti).second;
for (size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
}
cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.empty());
cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.is_empty());
}
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
@ -1286,14 +1283,11 @@ copy_tags(PandaNode *other) {
void PandaNode::
list_tags(ostream &out, const string &separator) const {
CDReader cdata(_cycler);
if (!cdata->_tag_data.empty()) {
TagData::const_iterator ti = cdata->_tag_data.begin();
out << (*ti).first;
++ti;
while (ti != cdata->_tag_data.end()) {
out << separator << (*ti).first;
++ti;
for (size_t n = 0; n < cdata->_tag_data.size(); ++n) {
if (n > 0) {
out << separator;
}
out << cdata->_tag_data.get_key(n);
}
// We used to list the Python tags here. That's a bit awkward, though,
@ -1310,12 +1304,8 @@ list_tags(ostream &out, const string &separator) const {
void PandaNode::
get_tag_keys(vector_string &keys) const {
CDReader cdata(_cycler);
if (!cdata->_tag_data.empty()) {
TagData::const_iterator ti = cdata->_tag_data.begin();
while (ti != cdata->_tag_data.end()) {
keys.push_back((*ti).first);
++ti;
}
for (size_t n = 0; n < cdata->_tag_data.size(); ++n) {
keys.push_back(cdata->_tag_data.get_key(n));
}
}
@ -1331,28 +1321,30 @@ compare_tags(const PandaNode *other) const {
CDReader cdata(_cycler);
CDReader cdata_other(other->_cycler);
TagData::const_iterator ati = cdata->_tag_data.begin();
TagData::const_iterator bti = cdata_other->_tag_data.begin();
while (ati != cdata->_tag_data.end() &&
bti != cdata_other->_tag_data.end()) {
int cmp = strcmp((*ati).first.c_str(), (*bti).first.c_str());
const TagData &a_data = cdata->_tag_data;
const TagData &b_data = cdata_other->_tag_data;
size_t ai = 0;
size_t bi = 0;
while (ai < a_data.size() && bi < b_data.size()) {
int cmp = strcmp(a_data.get_key(ai).c_str(), b_data.get_key(bi).c_str());
if (cmp != 0) {
return cmp;
}
cmp = strcmp((*ati).second.c_str(), (*bti).second.c_str());
cmp = strcmp(a_data.get_key(ai).c_str(), b_data.get_key(bi).c_str());
if (cmp != 0) {
return cmp;
}
++ati;
++bti;
++ai;
++bi;
}
if (ati != cdata->_tag_data.end()) {
if (ai < a_data.size()) {
// list A is longer.
return 1;
}
if (bti != cdata_other->_tag_data.end()) {
if (bi < b_data.size()) {
// list B is longer.
return -1;
}
@ -1412,11 +1404,8 @@ copy_all_properties(PandaNode *other) {
// to preserve properties such as the default GeomNode bitmask.
cdataw->_into_collide_mask |= cdatar->_into_collide_mask;
TagData::const_iterator ti;
for (ti = cdatar->_tag_data.begin();
ti != cdatar->_tag_data.end();
++ti) {
cdataw->_tag_data[(*ti).first] = (*ti).second;
for (size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
}
static const int change_bits = (FB_transform | FB_state | FB_effects |
@ -3775,13 +3764,11 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
dg.add_uint8(_bounds_type);
dg.add_uint32(_tag_data.size());
TagData::const_iterator ti;
for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
dg.add_string((*ti).first);
dg.add_string((*ti).second);
for (size_t n = 0; n < _tag_data.size(); ++n) {
dg.add_string(_tag_data.get_key(n));
dg.add_string(_tag_data.get_data(n));
}
write_up_list(*get_up(), manager, dg);
write_down_list(*get_down(), manager, dg);
write_down_list(*get_stashed(), manager, dg);
@ -3855,7 +3842,7 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
set_fancy_bit(FB_transform, !_transform->is_identity());
set_fancy_bit(FB_state, !_state->is_empty());
set_fancy_bit(FB_effects, !_effects->is_empty());
set_fancy_bit(FB_tag, !_tag_data.empty());
set_fancy_bit(FB_tag, !_tag_data.is_empty());
// Mark the bounds stale.
++_next_update;
@ -3914,7 +3901,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
for (int i = 0; i < num_tags; i++) {
string key = scan.get_string();
string value = scan.get_string();
_tag_data[key] = value;
_tag_data.store(key, value);
}

View File

@ -45,6 +45,7 @@
#include "copyOnWritePointer.h"
#include "lightReMutex.h"
#include "extension.h"
#include "simpleHashMap.h"
class NodePathComponent;
class CullTraverser;
@ -196,7 +197,15 @@ PUBLISHED:
Thread *current_thread = Thread::get_current_thread()) const;
void clear_tag(const string &key,
Thread *current_thread = Thread::get_current_thread());
public:
void get_tag_keys(vector_string &keys) const;
INLINE size_t get_num_tags() const;
INLINE string get_tag_key(size_t i) const;
PUBLISHED:
MAKE_MAP_PROPERTY(tags, has_tag, get_tag, set_tag, clear_tag);
MAKE_MAP_KEYS_SEQ(tags, get_num_tags, get_tag_key);
EXTENSION(PyObject *get_tag_keys() const);
@ -511,7 +520,7 @@ private:
// This is used to maintain a table of keyed data on each node, for the
// user's purposes.
typedef phash_map<string, string, string_hash> TagData;
typedef SimpleHashMap<string, string, string_hash> TagData;
// This is actually implemented in pandaNode_ext.h, but defined here so
// that we can destruct it from the C++ side. Note that it isn't cycled,

View File

@ -97,8 +97,9 @@ is_empty() const {
/**
* Returns the number of separate effects indicated in the state.
* @deprecated in Python, use len(effects) instead, or effects.size() in C++.
*/
INLINE int RenderEffects::
INLINE size_t RenderEffects::
get_num_effects() const {
return _effects.size();
}
@ -107,11 +108,36 @@ get_num_effects() const {
* Returns the nth effect in the state.
*/
INLINE const RenderEffect *RenderEffects::
get_effect(int n) const {
nassertr(n >= 0 && n < (int)_effects.size(), NULL);
get_effect(size_t n) const {
nassertr(n < _effects.size(), nullptr);
return _effects[n]._effect;
}
/**
* Returns the number of separate effects indicated in the state.
*/
INLINE size_t RenderEffects::
size() const {
return _effects.size();
}
/**
* Returns the nth effect in the state.
*/
INLINE const RenderEffect *RenderEffects::
operator [](size_t n) const {
nassertr(n < _effects.size(), nullptr);
return _effects[n]._effect;
}
/**
* Returns the effect in the state with the given type.
*/
INLINE const RenderEffect *RenderEffects::
operator [](TypeHandle type) const {
return get_effect(type);
}
/**
* This function is provided as an optimization, to speed up the render-time
* checking for the existance of a DecalEffect on this state. It returns true

View File

@ -58,8 +58,12 @@ PUBLISHED:
bool operator < (const RenderEffects &other) const;
INLINE bool is_empty() const;
INLINE int get_num_effects() const;
INLINE const RenderEffect *get_effect(int n) const;
INLINE size_t get_num_effects() const;
INLINE const RenderEffect *get_effect(size_t n) const;
INLINE size_t size() const;
INLINE const RenderEffect *operator [] (size_t n) const;
INLINE const RenderEffect *operator [] (TypeHandle type) const;
int find_effect(TypeHandle type) const;

View File

@ -65,7 +65,12 @@ PUBLISHED:
int find_on_stage(const TextureStage *stage) const;
MAKE_SEQ_PROPERTY(on_stages, get_num_on_stages, get_on_stage);
MAKE_MAP_PROPERTY(on_stages, find_on_stage, get_on_stage);
MAKE_MAP_PROPERTY(textures, has_on_stage, get_on_texture);
MAKE_MAP_KEYS_SEQ(textures, get_num_on_stages, get_on_stage);
MAKE_MAP_PROPERTY(samplers, has_on_stage, get_on_sampler);
MAKE_MAP_KEYS_SEQ(samplers, get_num_on_stages, get_on_stage);
INLINE int get_num_off_stages() const;
INLINE TextureStage *get_off_stage(int n) const;
@ -74,7 +79,6 @@ PUBLISHED:
INLINE bool has_all_off() const;
MAKE_SEQ_PROPERTY(off_stages, get_num_off_stages, get_off_stage);
MAKE_MAP_PROPERTY(off_stages, has_off_stage, get_off_stage);
INLINE bool is_identity() const;

View File

@ -71,6 +71,21 @@ set_dispatch(size_t n, const LVecBase3i &dispatch) {
cdata->_dispatches[n] = dispatch;
}
/**
* Inserts a dispatch command with the given number of work groups in the X,
* Y, and Z dimensions at the given position in the list of dispatch commands.
* Any of these values may be set to 1 if the respective dimension should not
* be used.
*/
INLINE void ComputeNode::
insert_dispatch(size_t n, const LVecBase3i &dispatch) {
Dispatcher::CDWriter cdata(_dispatcher->_cycler);
if (n > cdata->_dispatches.size()) {
n = cdata->_dispatches.size();
}
cdata->_dispatches.insert(cdata->_dispatches.begin(), dispatch);
}
/**
* Erases the given dispatch index from the list.
*/

View File

@ -34,11 +34,12 @@ PUBLISHED:
INLINE size_t get_num_dispatches() const;
INLINE const LVecBase3i &get_dispatch(size_t i) const;
INLINE void set_dispatch(size_t i, const LVecBase3i &num_groups);
INLINE void insert_dispatch(size_t i, const LVecBase3i &num_groups);
INLINE void remove_dispatch(size_t i);
INLINE void clear_dispatches();
MAKE_SEQ(get_dispatches, get_num_dispatches, get_dispatch);
MAKE_SEQ_PROPERTY(dispatches, get_num_dispatches, get_dispatch, set_dispatch, remove_dispatch);
MAKE_SEQ_PROPERTY(dispatches, get_num_dispatches, get_dispatch, set_dispatch, remove_dispatch, insert_dispatch);
public:
ComputeNode(const ComputeNode &copy);

View File

@ -69,15 +69,29 @@ add_forces_from(const ForceNode &other) {
*/
void ForceNode::
set_force(size_t index, BaseForce *force) {
nassertv(index <= _forces.size());
nassertv(index < _forces.size());
_forces[index]->_force_node = (ForceNode *)NULL;
_forces[index]->_force_node = nullptr;
_forces[index]->_force_node_path.clear();
_forces[index] = force;
force->_force_node = this;
force->_force_node_path = NodePath(this);
}
/**
* insert operation
*/
void ForceNode::
insert_force(size_t index, BaseForce *force) {
if (index > _forces.size()) {
index = _forces.size();
}
_forces.insert(_forces.begin() + index, force);
force->_force_node = this;
force->_force_node_path = NodePath(this);
}
/**
* remove operation
*/

View File

@ -35,10 +35,11 @@ PUBLISHED:
void add_forces_from(const ForceNode &other);
void set_force(size_t index, BaseForce *force);
void insert_force(size_t index, BaseForce *force);
void remove_force(BaseForce *force);
void remove_force(size_t index);
MAKE_SEQ_PROPERTY(forces, get_num_forces, get_force, set_force, remove_force);
MAKE_SEQ_PROPERTY(forces, get_num_forces, get_force, set_force, remove_force, insert_force);
virtual void output(ostream &out) const;
virtual void write_forces(ostream &out, unsigned int indent=0) const;

View File

@ -77,13 +77,26 @@ add_physicals_from(const PhysicalNode &other) {
*/
void PhysicalNode::
set_physical(size_t index, Physical *physical) {
nassertv(index <= _physicals.size());
nassertv(index < _physicals.size());
_physicals[index]->_physical_node = (PhysicalNode *) NULL;
_physicals[index]->_physical_node = nullptr;
_physicals[index] = physical;
physical->_physical_node = this;
}
/**
* insert operation
*/
void PhysicalNode::
insert_physical(size_t index, Physical *physical) {
if (index > _physicals.size()) {
index = _physicals.size();
}
_physicals.insert(_physicals.begin() + index, physical);
physical->_physical_node = this;
}
/**
* remove operation
*/

View File

@ -36,10 +36,12 @@ PUBLISHED:
void add_physicals_from(const PhysicalNode &other);
void set_physical(size_t index, Physical *physical);
void insert_physical(size_t index, Physical *physical);
void remove_physical(Physical *physical);
void remove_physical(size_t index);
MAKE_SEQ_PROPERTY(physicals, get_num_physicals, get_physical, set_physical, remove_physical);
MAKE_SEQ_PROPERTY(physicals, get_num_physicals, get_physical, set_physical,
remove_physical, insert_physical);
virtual void write(ostream &out, unsigned int indent=0) const;

View File

@ -25,6 +25,25 @@ SimpleHashMap(const Compare &comp) :
{
}
/**
*
*/
template<class Key, class Value, class Compare>
INLINE SimpleHashMap<Key, Value, Compare>::
SimpleHashMap(const SimpleHashMap &copy) :
_table_size(copy._table_size),
_num_entries(copy._num_entries),
_comp(copy._comp) {
// We allocate enough bytes for _table_size elements of TableEntry, plus
// _table_size * 4 more ints at the end (for the index array).
size_t alloc_size = _table_size * (sizeof(TableEntry) + sizeof(int) * sparsity);
_deleted_chain = memory_hook->get_deleted_chain(alloc_size);
_table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none());
memcpy(_table, copy._table, alloc_size);
}
/**
*
*/
@ -37,7 +56,10 @@ SimpleHashMap(SimpleHashMap &&from) NOEXCEPT :
_num_entries(from._num_entries),
_comp(move(from._comp))
{
from._table = nullptr;
from._deleted_chain = nullptr;
from._table_size = 0;
from._num_entries = 0;
}
/**
@ -49,6 +71,48 @@ INLINE SimpleHashMap<Key, Value, Compare>::
clear();
}
/**
*
*/
template<class Key, class Value, class Compare>
INLINE SimpleHashMap<Key, Value, Compare> &SimpleHashMap<Key, Value, Compare>::
operator = (const SimpleHashMap<Key, Value, Compare> &copy) {
if (this != &copy) {
_table_size = copy._table_size;
_num_entries = copy._num_entries;
_comp = copy._comp;
// We allocate enough bytes for _table_size elements of TableEntry, plus
// _table_size * 4 more ints at the end (for the index array).
size_t alloc_size = _table_size * (sizeof(TableEntry) + sizeof(int) * sparsity);
_deleted_chain = memory_hook->get_deleted_chain(alloc_size);
_table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none());
memcpy(_table, copy._table, alloc_size);
}
return *this;
}
/**
*
*/
template<class Key, class Value, class Compare>
INLINE SimpleHashMap<Key, Value, Compare> &SimpleHashMap<Key, Value, Compare>::
operator = (SimpleHashMap<Key, Value, Compare> &&from) NOEXCEPT {
if (this != &from) {
_table = from._table;
_deleted_chain = from._deleted_chain;
_table_size = from._table_size;
_num_entries = from._num_entries;
_comp = move(from._comp);
from._table = nullptr;
from._deleted_chain = nullptr;
from._table_size = 0;
from._num_entries = 0;
}
}
/**
* Quickly exchanges the contents of this map and the other map.
*/

View File

@ -86,9 +86,13 @@ class SimpleHashMap {
public:
#ifndef CPPPARSER
CONSTEXPR SimpleHashMap(const Compare &comp = Compare());
INLINE SimpleHashMap(const SimpleHashMap &copy);
INLINE SimpleHashMap(SimpleHashMap &&from) NOEXCEPT;
INLINE ~SimpleHashMap();
INLINE SimpleHashMap &operator = (const SimpleHashMap &copy);
INLINE SimpleHashMap &operator = (SimpleHashMap &&from) NOEXCEPT;
INLINE void swap(SimpleHashMap &other);
int find(const Key &key) const;

View File

@ -53,18 +53,31 @@ def test_fbquality_rgba64():
# This issue occurs if we are requesting 1 bit, not if we are requesting
# a specific amount. There are several ways to do that, so we want to
# assert that none of them will yield a 64-bit color buffer.
req_color = FrameBufferProperties()
req_color.color_bits = 1
req_color0 = FrameBufferProperties()
req_color0.color_bits = 0
req_color_alpha = FrameBufferProperties()
req_color_alpha.color_bits = 1
req_color_alpha.alpha_bits = 1
req_color1 = FrameBufferProperties()
req_color1.color_bits = 1
req_rgb = FrameBufferProperties()
req_rgb.set_rgba_bits(1, 1, 1, 0)
req_color0_alpha0 = FrameBufferProperties()
req_color0_alpha0.color_bits = 0
req_color0_alpha0.alpha_bits = 0
req_rgb_alpha = FrameBufferProperties()
req_rgb_alpha.set_rgba_bits(1, 1, 1, 1)
req_color1_alpha1 = FrameBufferProperties()
req_color1_alpha1.color_bits = 1
req_color1_alpha1.alpha_bits = 1
req_rgb0 = FrameBufferProperties()
req_rgb0.set_rgba_bits(0, 0, 0, 0)
req_rgb1 = FrameBufferProperties()
req_rgb1.set_rgba_bits(1, 1, 1, 0)
req_rgb0_alpha0 = FrameBufferProperties()
req_rgb0_alpha0.set_rgba_bits(0, 0, 0, 0)
req_rgb1_alpha1 = FrameBufferProperties()
req_rgb1_alpha1.set_rgba_bits(1, 1, 1, 1)
fb_rgba8 = FrameBufferProperties()
fb_rgba8.rgb_color = True
@ -74,7 +87,11 @@ def test_fbquality_rgba64():
fb_rgba16.rgb_color = True
fb_rgba16.set_rgba_bits(16, 16, 16, 16)
assert fb_rgba8.get_quality(req_color) > fb_rgba16.get_quality(req_color)
assert fb_rgba8.get_quality(req_color_alpha) > fb_rgba16.get_quality(req_color_alpha)
assert fb_rgba8.get_quality(req_rgb) > fb_rgba16.get_quality(req_rgb)
assert fb_rgba8.get_quality(req_rgb_alpha) > fb_rgba16.get_quality(req_rgb_alpha)
assert fb_rgba8.get_quality(req_color0) > fb_rgba16.get_quality(req_color0)
assert fb_rgba8.get_quality(req_color1) > fb_rgba16.get_quality(req_color1)
assert fb_rgba8.get_quality(req_color0_alpha0) > fb_rgba16.get_quality(req_color0_alpha0)
assert fb_rgba8.get_quality(req_color1_alpha1) > fb_rgba16.get_quality(req_color1_alpha1)
assert fb_rgba8.get_quality(req_rgb0) > fb_rgba16.get_quality(req_rgb0)
assert fb_rgba8.get_quality(req_rgb1) > fb_rgba16.get_quality(req_rgb1)
assert fb_rgba8.get_quality(req_rgb0_alpha0) > fb_rgba16.get_quality(req_rgb0_alpha0)
assert fb_rgba8.get_quality(req_rgb1_alpha1) > fb_rgba16.get_quality(req_rgb1_alpha1)

View File

@ -2,6 +2,7 @@ import sys
import pytest
from panda3d import core
from contextlib import contextmanager
import collections
@contextmanager
@ -70,6 +71,15 @@ item_b = core.CollisionSphere((0, 0, 0), 2)
item_c = core.CollisionSphere((0, 0, 0), 3)
def test_seq_property_abc():
prop = seq_property()
assert isinstance(prop, collections.Container)
assert isinstance(prop, collections.Sized)
assert isinstance(prop, collections.Iterable)
assert isinstance(prop, collections.MutableSequence)
assert isinstance(prop, collections.Sequence)
def test_seq_property_empty():
prop = seq_property()
assert not prop
@ -92,6 +102,11 @@ def test_seq_property_iter():
assert None not in prop
def test_seq_property_reversed():
prop = seq_property(item_a, item_b, item_b)
assert tuple(reversed(prop)) == tuple(reversed(tuple(prop)))
def test_seq_property_getitem():
prop = seq_property(item_a, item_b, item_b)
@ -313,6 +328,88 @@ def test_seq_property_remove():
prop.remove("nonsense")
def test_seq_property_append():
prop = seq_property(item_a, item_b)
with constant_refcount(item_c):
prop.append(item_c)
assert tuple(prop) == (item_a, item_b, item_c)
with pytest.raises(TypeError):
prop.append(None)
with pytest.raises(TypeError):
prop.append("nonsense")
def test_seq_property_insert():
# Adding at the beginning
prop = seq_property(item_a, item_a, item_a)
with constant_refcount(item_b):
prop.insert(0, item_b)
assert tuple(prop) == (item_b, item_a, item_a, item_a)
# Adding in the middle
prop = seq_property(item_a, item_a, item_a)
with constant_refcount(item_b):
prop.insert(2, item_b)
assert tuple(prop) == (item_a, item_a, item_b, item_a)
# Adding at the end
prop = seq_property(item_a, item_a, item_a)
with constant_refcount(item_b):
prop.insert(len(prop), item_b)
assert tuple(prop) == (item_a, item_a, item_a, item_b)
# Adding with negative index
prop = seq_property(item_a, item_a, item_a)
with constant_refcount(item_b):
prop.insert(-2, item_b)
assert tuple(prop) == (item_a, item_b, item_a, item_a)
# Adding at the end with overflowing index
prop = seq_property(item_a, item_a, item_a)
with constant_refcount(item_b):
prop.insert(2345, item_b)
assert tuple(prop) == (item_a, item_a, item_a, item_b)
# Adding at the beginning with negative overflowing index
prop = seq_property(item_a, item_a, item_a)
with constant_refcount(item_b):
prop.insert(-2345, item_b)
assert tuple(prop) == (item_b, item_a, item_a, item_a)
def test_seq_property_extend():
prop = seq_property(item_a)
with constant_refcount(item_b):
prop.extend((item_b, item_c))
assert tuple(prop) == (item_a, item_b, item_c)
with pytest.raises(TypeError):
prop.extend(None)
with pytest.raises(TypeError):
prop.extend("nonsense")
with pytest.raises(TypeError):
prop.extend(item_a)
with pytest.raises(TypeError):
prop.extend(item_a, item_b)
with pytest.raises(TypeError):
prop.extend()
with pytest.raises(TypeError):
prop.extend((item_a, None))
with pytest.raises(TypeError):
prop.extend(["nonsense"])
# The next tests are for MAKE_MAP_PROPERTY.
@pytest.fixture
def map_property(**items):
@ -326,6 +423,27 @@ def map_property(**items):
return np.tags
def test_map_property_abc():
prop = map_property()
assert isinstance(prop, collections.Container)
assert isinstance(prop, collections.Sized)
assert isinstance(prop, collections.Iterable)
assert isinstance(prop, collections.MutableMapping)
assert isinstance(prop, collections.Mapping)
def test_map_property_empty():
prop = map_property()
assert not prop
assert len(prop) == 0
with pytest.raises(KeyError):
prop.popitem()
with pytest.raises(KeyError):
prop['nonsense']
def test_map_property_getitem():
key = 'key'
value = 'value'
@ -430,6 +548,24 @@ def test_map_property_pop():
assert 'key' not in prop
def test_map_property_popitem():
key = 'key'
value = 'value'
prop = map_property(**{key: value})
assert prop.popitem() == (key, value)
with pytest.raises(KeyError):
assert prop.popitem()
def test_map_property_clear():
prop = map_property(key='value', key2='value2')
prop.clear()
assert len(prop) == 0
def test_map_property_setdefault():
prop = map_property(key='value')
@ -466,3 +602,24 @@ def test_map_property_update():
assert prop['key'] == 'value'
assert prop['key2'] == 'value2'
def test_map_property_keys():
prop = map_property(key='value', key2='value2')
assert isinstance(prop.keys(), collections.MappingView)
assert frozenset(prop.keys()) == frozenset(('key', 'key2'))
def test_map_property_values():
prop = map_property(key='value', key2='value2')
assert isinstance(prop.values(), collections.ValuesView)
assert frozenset(prop.values()) == frozenset(('value', 'value2'))
def test_map_property_items():
prop = map_property(key='value', key2='value2')
assert isinstance(prop.items(), collections.MappingView)
assert frozenset(prop.items()) == frozenset((('key', 'value'), ('key2', 'value2')))