array ranges

This commit is contained in:
David Rose 2004-06-22 17:34:24 +00:00
parent ff5701c89a
commit e9027a1daf
10 changed files with 654 additions and 382 deletions

View File

@ -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 &copy) :
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);
}

View File

@ -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 &copy);
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

View File

@ -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

View File

@ -39,7 +39,10 @@ public:
INLINE void operator = (const DCNumericRange &copy);
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;

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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);
}
;

View File

@ -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;
}
}
}