array ranges
This commit is contained in:
parent
ff5701c89a
commit
e9027a1daf
|
|
@ -25,19 +25,28 @@
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCArrayParameter::
|
||||
DCArrayParameter(DCParameter *element_type, int array_size) :
|
||||
DCArrayParameter(DCParameter *element_type, const DCUnsignedIntRange &size) :
|
||||
_element_type(element_type),
|
||||
_array_size(array_size)
|
||||
_array_size_range(size)
|
||||
{
|
||||
set_name(_element_type->get_name());
|
||||
_element_type->set_name(string());
|
||||
|
||||
_array_size = -1;
|
||||
if (_array_size_range.has_one_value()) {
|
||||
_array_size = _array_size_range.get_one_value();
|
||||
}
|
||||
|
||||
if (_array_size >= 0 && _element_type->has_fixed_byte_size()) {
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = _array_size * _element_type->get_fixed_byte_size();
|
||||
|
||||
} else {
|
||||
// We only need to store the length bytes if the array has a
|
||||
// variable size.
|
||||
_num_length_bytes = 2;
|
||||
}
|
||||
|
||||
_num_length_bytes = 2;
|
||||
_has_nested_fields = true;
|
||||
_num_nested_fields = _array_size;
|
||||
_pack_type = PT_array;
|
||||
|
|
@ -52,7 +61,8 @@ DCArrayParameter::
|
|||
DCArrayParameter(const DCArrayParameter ©) :
|
||||
DCParameter(copy),
|
||||
_element_type(copy._element_type->make_copy()),
|
||||
_array_size(copy._array_size)
|
||||
_array_size(copy._array_size),
|
||||
_array_size_range(copy._array_size_range)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +123,7 @@ get_element_type() const {
|
|||
// Function: DCArrayParameter::get_array_size
|
||||
// Access: Published
|
||||
// Description: Returns the fixed number of elements in this array,
|
||||
// or -1 if the array may contain any number of
|
||||
// or -1 if the array may contain a variable number of
|
||||
// elements.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DCArrayParameter::
|
||||
|
|
@ -152,6 +162,24 @@ get_nested_field(int) const {
|
|||
return _element_type;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCArrayParameter::validate_num_nested_fields
|
||||
// Access: Public, Virtual
|
||||
// Description: After a number of fields have been packed via push()
|
||||
// .. pack_*() .. pop(), this is called to confirm that
|
||||
// the number of nested fields that were added is valid
|
||||
// for this type. This is primarily useful for array
|
||||
// types with dynamic ranges that can't validate the
|
||||
// number of fields any other way.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DCArrayParameter::
|
||||
validate_num_nested_fields(int num_nested_fields) const {
|
||||
bool range_error = false;
|
||||
_array_size_range.validate(num_nested_fields, range_error);
|
||||
|
||||
return !range_error;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCArrayParameter::output_instance
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -167,11 +195,9 @@ output_instance(ostream &out, const string &prename, const string &name,
|
|||
} else {
|
||||
ostringstream strm;
|
||||
|
||||
if (_array_size >= 0) {
|
||||
strm << "[" << _array_size << "]";
|
||||
} else {
|
||||
strm << "[]";
|
||||
}
|
||||
strm << "[";
|
||||
_array_size_range.output(strm);
|
||||
strm << "]";
|
||||
|
||||
_element_type->output_instance(out, prename, name, strm.str() + postname);
|
||||
}
|
||||
|
|
@ -187,5 +213,5 @@ void DCArrayParameter::
|
|||
generate_hash(HashGenerator &hashgen) const {
|
||||
DCParameter::generate_hash(hashgen);
|
||||
_element_type->generate_hash(hashgen);
|
||||
hashgen.add_int(_array_size);
|
||||
_array_size_range.generate_hash(hashgen);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "dcbase.h"
|
||||
#include "dcParameter.h"
|
||||
#include "dcNumericRange.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DCArrayParameter
|
||||
|
|
@ -31,7 +32,8 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_DIRECT DCArrayParameter : public DCParameter {
|
||||
public:
|
||||
DCArrayParameter(DCParameter *element_type, int array_size = -1);
|
||||
DCArrayParameter(DCParameter *element_type,
|
||||
const DCUnsignedIntRange &size = DCUnsignedIntRange());
|
||||
DCArrayParameter(const DCArrayParameter ©);
|
||||
virtual ~DCArrayParameter();
|
||||
|
||||
|
|
@ -46,6 +48,7 @@ PUBLISHED:
|
|||
public:
|
||||
virtual int calc_num_nested_fields(size_t length_bytes) const;
|
||||
virtual DCPackerInterface *get_nested_field(int n) const;
|
||||
virtual bool validate_num_nested_fields(int num_nested_fields) const;
|
||||
|
||||
virtual void output_instance(ostream &out, const string &prename,
|
||||
const string &name, const string &postname) const;
|
||||
|
|
@ -54,6 +57,7 @@ public:
|
|||
private:
|
||||
DCParameter *_element_type;
|
||||
int _array_size;
|
||||
DCUnsignedIntRange _array_size_range;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -90,16 +90,41 @@ is_in_range(Number num) const {
|
|||
// Description: Convenience function to validate the indicated
|
||||
// number. If the number is within the specified range,
|
||||
// does nothing; otherwise, if it is outside the range,
|
||||
// sets validation_error to true.
|
||||
// sets range_error to true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template <class NUM>
|
||||
INLINE void DCNumericRange<NUM>::
|
||||
validate(Number num, bool &validation_error) const {
|
||||
validate(Number num, bool &range_error) const {
|
||||
if (!is_in_range(num)) {
|
||||
validation_error = true;
|
||||
range_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCNumericRange::has_one_value
|
||||
// Access: Public
|
||||
// Description: Returns true if the numeric range specifies exactly
|
||||
// one legal value, false if multiple values are legal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template <class NUM>
|
||||
INLINE bool DCNumericRange<NUM>::
|
||||
has_one_value() const {
|
||||
return _ranges.size() == 1 && _ranges[0]._min == _ranges[0]._max;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCNumericRange::get_one_value
|
||||
// Access: Public
|
||||
// Description: If has_one_value() returns true, this returns the one
|
||||
// legal value accepted by the numeric range.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template <class NUM>
|
||||
INLINE DCNumericRange<NUM>::Number DCNumericRange<NUM>::
|
||||
get_one_value() const {
|
||||
nassertr(has_one_value(), 0);
|
||||
return _ranges[0]._min;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCNumericRange::generate_hash
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -39,7 +39,10 @@ public:
|
|||
INLINE void operator = (const DCNumericRange ©);
|
||||
|
||||
bool is_in_range(Number num) const;
|
||||
INLINE void validate(Number num, bool &validation_error) const;
|
||||
INLINE void validate(Number num, bool &range_error) const;
|
||||
|
||||
INLINE bool has_one_value() const;
|
||||
INLINE Number get_one_value() const;
|
||||
|
||||
void generate_hash(HashGenerator &hashgen) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -463,6 +463,11 @@ pop() {
|
|||
_pack_error = true;
|
||||
|
||||
} else {
|
||||
if (!_current_parent->validate_num_nested_fields(_current_field_index)) {
|
||||
// Incorrect number of nested elements.
|
||||
_pack_error = true;
|
||||
}
|
||||
|
||||
if (_mode == M_pack || _mode == M_repack) {
|
||||
size_t length_bytes = _current_parent->get_num_length_bytes();
|
||||
if (length_bytes != 0) {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,21 @@ get_nested_field(int n) const {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerInterface::validate_num_nested_fields
|
||||
// Access: Public, Virtual
|
||||
// Description: After a number of fields have been packed via push()
|
||||
// .. pack_*() .. pop(), this is called to confirm that
|
||||
// the number of nested fields that were added is valid
|
||||
// for this type. This is primarily useful for array
|
||||
// types with dynamic ranges that can't validate the
|
||||
// number of fields any other way.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DCPackerInterface::
|
||||
validate_num_nested_fields(int) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerInterface::pack_double
|
||||
// Access: Public, Virtual
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ public:
|
|||
virtual int calc_num_nested_fields(size_t length_bytes) const;
|
||||
virtual DCPackerInterface *get_nested_field(int n) const;
|
||||
|
||||
virtual bool validate_num_nested_fields(int num_nested_fields) const;
|
||||
|
||||
INLINE DCPackType get_pack_type() const;
|
||||
|
||||
virtual void pack_double(DCPackData &pack_data, double value,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -34,6 +34,7 @@ static DCParameter *current_parameter = (DCParameter *)NULL;
|
|||
static DCPacker default_packer;
|
||||
static DCPacker *current_packer;
|
||||
static DCDoubleRange double_range;
|
||||
static DCUnsignedIntRange uint_range;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Defining the interface to the parser.
|
||||
|
|
@ -460,8 +461,7 @@ double_range:
|
|||
double_range.clear();
|
||||
if ($2 >= 0) {
|
||||
yyerror("Syntax error");
|
||||
}
|
||||
if (!double_range.add_range($1, -$2)) {
|
||||
} else if (!double_range.add_range($1, -$2)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
|
|
@ -481,8 +481,73 @@ double_range:
|
|||
{
|
||||
if ($4 >= 0) {
|
||||
yyerror("Syntax error");
|
||||
} else if (!double_range.add_range($3, -$4)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
if (!double_range.add_range($3, -$4)) {
|
||||
}
|
||||
;
|
||||
|
||||
uint_range:
|
||||
empty
|
||||
{
|
||||
uint_range.clear();
|
||||
}
|
||||
| INTEGER
|
||||
{
|
||||
if ($1 < 0) {
|
||||
yyerror("Nonnegative values only");
|
||||
} else {
|
||||
uint_range.clear();
|
||||
if (!uint_range.add_range($1, $1)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
}
|
||||
| INTEGER '-' INTEGER
|
||||
{
|
||||
if ($1 < 0 || $3 < 0) {
|
||||
yyerror("Nonnegative values only");
|
||||
} else {
|
||||
uint_range.clear();
|
||||
if (!uint_range.add_range($1, $3)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
}
|
||||
| INTEGER INTEGER
|
||||
{
|
||||
uint_range.clear();
|
||||
if ($2 >= 0) {
|
||||
yyerror("Syntax error");
|
||||
} else if ($1 < 0) {
|
||||
yyerror("Nonnegative values only");
|
||||
} else if (!uint_range.add_range($1, -$2)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
| uint_range ',' INTEGER
|
||||
{
|
||||
if ($3 < 0) {
|
||||
yyerror("Nonnegative values only");
|
||||
} else if (!uint_range.add_range($3, $3)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
| uint_range ',' INTEGER '-' INTEGER
|
||||
{
|
||||
if ($3 < 0 || $5 < 0) {
|
||||
yyerror("Nonnegative values only");
|
||||
} else if (!uint_range.add_range($3, $5)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
| uint_range ',' INTEGER INTEGER
|
||||
{
|
||||
if ($4 >= 0) {
|
||||
yyerror("Syntax error");
|
||||
} else if ($3 < 0) {
|
||||
yyerror("Nonnegative values only");
|
||||
} else if (!uint_range.add_range($3, -$4)) {
|
||||
yyerror("Overlapping range");
|
||||
}
|
||||
}
|
||||
|
|
@ -490,13 +555,9 @@ double_range:
|
|||
|
||||
type_definition:
|
||||
type_name
|
||||
| type_definition '[' ']'
|
||||
| type_definition '[' uint_range ']'
|
||||
{
|
||||
$$ = new DCArrayParameter($1);
|
||||
}
|
||||
| type_definition '[' INTEGER ']'
|
||||
{
|
||||
$$ = new DCArrayParameter($1, $3);
|
||||
$$ = new DCArrayParameter($1, uint_range);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -520,13 +581,9 @@ parameter_definition:
|
|||
}
|
||||
}
|
||||
}
|
||||
| parameter_definition '[' ']'
|
||||
| parameter_definition '[' uint_range ']'
|
||||
{
|
||||
$$ = new DCArrayParameter($1);
|
||||
}
|
||||
| parameter_definition '[' INTEGER ']'
|
||||
{
|
||||
$$ = new DCArrayParameter($1, $3);
|
||||
$$ = new DCArrayParameter($1, uint_range);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -358,8 +358,6 @@ set_range(const DCDoubleRange &range) {
|
|||
|
||||
case ST_uint16:
|
||||
case ST_uint16array:
|
||||
case ST_string:
|
||||
case ST_blob:
|
||||
_uint_range.clear();
|
||||
for (i = 0; i < num_ranges; i++) {
|
||||
unsigned int min = (unsigned int)floor(range.get_min(i) * _divisor + 0.5);
|
||||
|
|
@ -372,7 +370,6 @@ set_range(const DCDoubleRange &range) {
|
|||
|
||||
case ST_uint32:
|
||||
case ST_uint32array:
|
||||
case ST_blob32:
|
||||
_uint_range.clear();
|
||||
for (i = 0; i < num_ranges; i++) {
|
||||
unsigned int min = (unsigned int)floor(range.get_min(i) * _divisor + 0.5);
|
||||
|
|
@ -399,6 +396,47 @@ set_range(const DCDoubleRange &range) {
|
|||
}
|
||||
break;
|
||||
|
||||
case ST_string:
|
||||
case ST_blob:
|
||||
_uint_range.clear();
|
||||
for (i = 0; i < num_ranges; i++) {
|
||||
unsigned int min = (unsigned int)floor(range.get_min(i) * _divisor + 0.5);
|
||||
unsigned int max = (unsigned int)floor(range.get_max(i) * _divisor + 0.5);
|
||||
validate_uint_limits(min, 16, range_error);
|
||||
validate_uint_limits(max, 16, range_error);
|
||||
_uint_range.add_range(min, max);
|
||||
}
|
||||
if (_uint_range.has_one_value()) {
|
||||
// If we now have a fixed-length string requirement, we don't
|
||||
// need a leading number of bytes.
|
||||
_num_length_bytes = 0;
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = _uint_range.get_one_value();
|
||||
} else {
|
||||
_num_length_bytes = 2;
|
||||
_has_fixed_byte_size = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_blob32:
|
||||
_uint_range.clear();
|
||||
for (i = 0; i < num_ranges; i++) {
|
||||
unsigned int min = (unsigned int)floor(range.get_min(i) * _divisor + 0.5);
|
||||
unsigned int max = (unsigned int)floor(range.get_max(i) * _divisor + 0.5);
|
||||
_uint_range.add_range(min, max);
|
||||
}
|
||||
if (_uint_range.has_one_value()) {
|
||||
// If we now have a fixed-length string requirement, we don't
|
||||
// need a leading number of bytes.
|
||||
_num_length_bytes = 0;
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = _uint_range.get_one_value();
|
||||
} else {
|
||||
_num_length_bytes = 4;
|
||||
_has_fixed_byte_size = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -811,12 +849,16 @@ pack_string(DCPackData &pack_data, const string &value,
|
|||
case ST_string:
|
||||
case ST_blob:
|
||||
validate_uint_limits(string_length, 16, range_error);
|
||||
do_pack_uint16(pack_data.get_write_pointer(2), string_length);
|
||||
if (_num_length_bytes != 0) {
|
||||
do_pack_uint16(pack_data.get_write_pointer(2), string_length);
|
||||
}
|
||||
pack_data.append_data(value.data(), string_length);
|
||||
break;
|
||||
|
||||
case ST_blob32:
|
||||
do_pack_uint32(pack_data.get_write_pointer(4), string_length);
|
||||
if (_num_length_bytes != 0) {
|
||||
do_pack_uint32(pack_data.get_write_pointer(4), string_length);
|
||||
}
|
||||
pack_data.append_data(value.data(), string_length);
|
||||
break;
|
||||
|
||||
|
|
@ -1488,30 +1530,36 @@ unpack_string(const char *data, size_t length, size_t &p, string &value,
|
|||
bool &pack_error, bool &range_error) const {
|
||||
size_t string_length;
|
||||
|
||||
switch (_type) {
|
||||
case ST_string:
|
||||
case ST_blob:
|
||||
if (p + 2 > length) {
|
||||
if (_num_length_bytes == 0) {
|
||||
string_length = _fixed_byte_size;
|
||||
|
||||
} else {
|
||||
switch (_type) {
|
||||
case ST_string:
|
||||
case ST_blob:
|
||||
if (p + 2 > length) {
|
||||
pack_error = true;
|
||||
return;
|
||||
}
|
||||
string_length = do_unpack_uint16(data + p);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
case ST_blob32:
|
||||
if (p + 4 > length) {
|
||||
pack_error = true;
|
||||
return;
|
||||
}
|
||||
string_length = do_unpack_uint32(data + p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
pack_error = true;
|
||||
return;
|
||||
}
|
||||
string_length = do_unpack_uint16(data + p);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
case ST_blob32:
|
||||
if (p + 4 > length) {
|
||||
pack_error = true;
|
||||
return;
|
||||
}
|
||||
string_length = do_unpack_uint32(data + p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
pack_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_uint_range.validate(string_length, range_error);
|
||||
|
||||
if (p + string_length > length) {
|
||||
|
|
@ -1647,7 +1695,10 @@ unpack_validate(const char *data, size_t length, size_t &p,
|
|||
|
||||
case ST_string:
|
||||
case ST_blob:
|
||||
{
|
||||
if (_num_length_bytes == 0) {
|
||||
p += _fixed_byte_size;
|
||||
|
||||
} else {
|
||||
if (p + 2 > length) {
|
||||
pack_error = true;
|
||||
return true;
|
||||
|
|
@ -1659,7 +1710,10 @@ unpack_validate(const char *data, size_t length, size_t &p,
|
|||
break;
|
||||
|
||||
case ST_blob32:
|
||||
{
|
||||
if (_num_length_bytes == 0) {
|
||||
p += _fixed_byte_size;
|
||||
|
||||
} else {
|
||||
if (p + 4 > length) {
|
||||
pack_error = true;
|
||||
return true;
|
||||
|
|
@ -1713,19 +1767,29 @@ unpack_skip(const char *data, size_t length, size_t &p) const {
|
|||
|
||||
case ST_string:
|
||||
case ST_blob:
|
||||
if (p + 2 > length) {
|
||||
return false;
|
||||
if (_num_length_bytes == 0) {
|
||||
p += _fixed_byte_size;
|
||||
|
||||
} else {
|
||||
if (p + 2 > length) {
|
||||
return false;
|
||||
}
|
||||
string_length = do_unpack_uint16(data + p);
|
||||
p += 2 + string_length;
|
||||
}
|
||||
string_length = do_unpack_uint16(data + p);
|
||||
p += 2 + string_length;
|
||||
break;
|
||||
|
||||
case ST_blob32:
|
||||
if (p + 4 > length) {
|
||||
return false;
|
||||
if (_num_length_bytes == 0) {
|
||||
p += _fixed_byte_size;
|
||||
|
||||
} else {
|
||||
if (p + 4 > length) {
|
||||
return false;
|
||||
}
|
||||
string_length = do_unpack_uint32(data + p);
|
||||
p += 4 + string_length;
|
||||
}
|
||||
string_length = do_unpack_uint32(data + p);
|
||||
p += 4 + string_length;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1749,7 +1813,7 @@ void DCSimpleParameter::
|
|||
output_instance(ostream &out, const string &prename, const string &name,
|
||||
const string &postname) const {
|
||||
if (get_typedef() != (DCTypedef *)NULL) {
|
||||
out << get_typedef()->get_name();
|
||||
output_typedef_name(out, prename, name, postname);
|
||||
|
||||
} else {
|
||||
out << _type;
|
||||
|
|
@ -1757,7 +1821,6 @@ output_instance(ostream &out, const string &prename, const string &name,
|
|||
out << "/" << _divisor;
|
||||
}
|
||||
|
||||
|
||||
switch (_type) {
|
||||
case ST_int8:
|
||||
case ST_int16:
|
||||
|
|
@ -1806,10 +1869,10 @@ output_instance(ostream &out, const string &prename, const string &name,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prename.empty() || !name.empty() || !postname.empty()) {
|
||||
out << " " << prename << name << postname;
|
||||
if (!prename.empty() || !name.empty() || !postname.empty()) {
|
||||
out << " " << prename << name << postname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue