Make prop_number_t handle both signed and unsigned numbers. The *integer*

routines now take int64_t arguments, and new *unsigned_integer* routines
take uint64_t arguments.  See prop_number(3) for complete details.
This commit is contained in:
thorpej 2006-10-12 04:46:56 +00:00
parent b5c9ebab95
commit 873293facc
5 changed files with 361 additions and 63 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: prop_number.h,v 1.3 2006/07/12 13:54:55 yamt Exp $ */
/* $NetBSD: prop_number.h,v 1.4 2006/10/12 04:46:56 thorpej Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@ -47,16 +47,20 @@
typedef struct _prop_number *prop_number_t;
__BEGIN_DECLS
prop_number_t prop_number_create_integer(uint64_t);
prop_number_t prop_number_create_integer(int64_t);
prop_number_t prop_number_create_unsigned_integer(uint64_t);
prop_number_t prop_number_copy(prop_number_t);
int prop_number_size(prop_number_t);
boolean_t prop_number_unsigned(prop_number_t);
uint64_t prop_number_integer_value(prop_number_t);
int64_t prop_number_integer_value(prop_number_t);
uint64_t prop_number_unsigned_integer_value(prop_number_t);
boolean_t prop_number_equals(prop_number_t, prop_number_t);
boolean_t prop_number_equals_integer(prop_number_t, uint64_t);
boolean_t prop_number_equals_integer(prop_number_t, int64_t);
boolean_t prop_number_equals_unsigned_integer(prop_number_t, uint64_t);
__END_DECLS
#endif /* _PROPLIB_PROP_NUMBER_H_ */

View File

@ -1,4 +1,4 @@
.\" $NetBSD: prop_number.3,v 1.3 2006/07/09 19:04:02 wiz Exp $
.\" $NetBSD: prop_number.3,v 1.4 2006/10/12 04:46:56 thorpej Exp $
.\"
.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -34,17 +34,21 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd April 22, 2006
.Dd October 11, 2006
.Dt PROP_NUMBER 3
.Os
.Sh NAME
.Nm prop_number ,
.Nm prop_number_create_integer ,
.Nm prop_number_create_unsigned_integer ,
.Nm prop_number_copy ,
.Nm prop_number_size ,
.Nm prop_number_unsigned ,
.Nm prop_number_integer_value ,
.Nm prop_number_unsigned_integer_value ,
.Nm prop_number_equals ,
.Nm prop_number_equals_integer
.Nm prop_number_equals_integer ,
.Nm prop_number_equals_unsigned_integer
.Nd numeric value property object
.Sh LIBRARY
.Lb libprop
@ -52,44 +56,111 @@
.In prop/proplib.h
.\"
.Ft prop_number_t
.Fn prop_number_create_integer "uint64_t val"
.Fn prop_number_create_integer "int64_t val"
.Ft prop_number_t
.Fn prop_number_create_unsigned_integer "uint64_t val"
.Ft prop_number_t
.Fn prop_numbery_copy "prop_number_t number"
.\"
.Ft int
.Fn prop_number_size "prop_number_t number"
.Ft uint64_t
.Ft boolean_t
.Fn prop_number_unsigned "prop_number_t number"
.Ft int64_t
.Fn prop_number_integer_value "prop_number_t number"
.Ft uint64_t
.Fn prop_number_unsigned_integer_value "prop_number_t number"
.\"
.Ft boolean_t
.Fn prop_number_equals "prop_number_t num1" "prop_number_t num2"
.Ft boolean_t
.Fn prop_number_equals_integer "prop_number_t number" "uint64_t val"
.Fn prop_number_equals_integer "prop_number_t number" "int64_t val"
.Ft boolean_t
.Fn prop_number_equals_unsigned_integer "prop_number_t number" "uint64_t val"
.Sh DESCRIPTION
The
.Nm prop_number
family of functions operate on a numeric value property object type.
All values are unsigned and promoted to the type
.Sq uint64_t .
Values are either signed or unsigned, and promoted to a 64-bit type
.Pq int64_t or uint64_t , respectively .
.Pp
It is possible to compare number objects that differ in sign.
Such comparisons first test to see if each object is within the valid
number range of the other:
.Bl -bullet
.It
Signed numbers that are greater than or equal to 0 can be compared to
unsigned numbers.
.It
Unsigned numbers that are less than or equal to the largest signed 64-bit
value
.Pq Dv INT64_MAX
can be compared to signed numbers.
.El
.Pp
Number objects have a different externalized representation depending
on their sign:
.Bl -bullet
.It
Signed numbers are externalized in base-10
.Pq decimal .
.It
Unsigned numbers are externalized in base-16
.Pq hexadecimal .
.El
.Pp
When numbers are internalized, the sign of the resulting number object
.Pq and thus its valid range
is determined by a set of rules evaluated in the following order:
.Bl -bullet
.It
If the first character of the number is a
.Sq -
then the number is signed.
.It
If the first two characters of the number are
.Sq 0x
then the number is unsigned.
.It
If the number value fits into the range of a signed number then the
number is signed.
.It
In all other cases, the number is unsigned.
.El
.Bl -tag -width "xxxxx"
.It Fn prop_number_create_integer "uint64_t val"
Create a numeric value object with the value
.It Fn prop_number_create_integer "int64_t val"
Create a numeric value object with the signed value
.Fa val .
.It Fn prop_number_create_unsigned_integer "uint64_t val"
Create a numeric value object with the unsigned value
.Fa val .
.It Fn prop_number_copy "prop_number_t number"
Copy a numeric value object.
.It Fn prop_number_size "prop_number_t number"
Returns 8, 16, 32, or 64, representing the number of bits required to
hold the value of the object.
.It Fn prop_number_unsigned "prop_number_t number"
Returns
.Dv
TRUE if the numeric value object has an unsigned value.
.It Fn prop_number_integer_value "prop_number_t number"
Returns the integer value of the numeric value object.
Returns the signed integer value of the numeric value object.
.It Fn prop_number_unsigned_integer_value "prop_number_t number"
Returns the unsigned integer value of the numeric value object.
.It Fn prop_number_equals "prop_number_t num1" "prop_number_t num2"
Returns
.Dv TRUE
if the two numeric value objects are equivalent.
.It Fn prop_number_equals_integer "prop_number_t number" "uint64_t val"
.It Fn prop_number_equals_integer "prop_number_t number" "int64_t val"
Returns
.Dv TRUE
if the object's value is equivalent to
if the object's value is equivalent to the signed value
.Fa val .
.It Fn prop_number_equals_unsigned_integer "prop_number_t number" \
"uint64_t val"
Returns
.Dv TRUE
if the object's value is equivalent to the unsigned value
.Fa val .
.El
.Sh SEE ALSO

View File

@ -1,4 +1,4 @@
/* $NetBSD: prop_number.c,v 1.7 2006/10/03 15:45:04 thorpej Exp $ */
/* $NetBSD: prop_number.c,v 1.8 2006/10/12 04:46:56 thorpej Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@ -53,7 +53,16 @@
struct _prop_number {
struct _prop_object pn_obj;
struct rb_node pn_link;
uint64_t pn_number;
struct _prop_number_value {
union {
int64_t pnu_signed;
uint64_t pnu_unsigned;
} pnv_un;
#define pnv_signed pnv_un.pnu_signed
#define pnv_unsigned pnv_un.pnu_unsigned
unsigned int pnv_is_unsigned :1,
:31;
} pn_value;
};
#define RBNODE_TO_PN(n) \
@ -84,6 +93,32 @@ static const struct _prop_object_type _prop_object_type_number = {
* numbers so we only have one copy of each.
*/
static int
_prop_number_compare_values(const struct _prop_number_value *pnv1,
const struct _prop_number_value *pnv2)
{
/* Signed numbers are sorted before unsigned numbers. */
if (pnv1->pnv_is_unsigned) {
if (! pnv2->pnv_is_unsigned)
return (1);
if (pnv1->pnv_unsigned < pnv2->pnv_unsigned)
return (-1);
if (pnv1->pnv_unsigned > pnv2->pnv_unsigned)
return (1);
return (0);
}
if (pnv2->pnv_is_unsigned)
return (-1);
if (pnv1->pnv_signed < pnv2->pnv_signed)
return (-1);
if (pnv1->pnv_signed > pnv2->pnv_signed)
return (1);
return (0);
}
static int
_prop_number_rb_compare_nodes(const struct rb_node *n1,
const struct rb_node *n2)
@ -91,11 +126,7 @@ _prop_number_rb_compare_nodes(const struct rb_node *n1,
const prop_number_t pn1 = RBNODE_TO_PN(n1);
const prop_number_t pn2 = RBNODE_TO_PN(n2);
if (pn1->pn_number < pn2->pn_number)
return (-1);
if (pn1->pn_number > pn2->pn_number)
return (1);
return (0);
return (_prop_number_compare_values(&pn1->pn_value, &pn2->pn_value));
}
static int
@ -103,13 +134,9 @@ _prop_number_rb_compare_key(const struct rb_node *n,
const void *v)
{
const prop_number_t pn = RBNODE_TO_PN(n);
const uint64_t *valp = v;
const struct _prop_number_value *pnv = v;
if (pn->pn_number < *valp)
return (-1);
if (pn->pn_number > *valp)
return (1);
return (0);
return (_prop_number_compare_values(&pn->pn_value, pnv));
}
static const struct rb_tree_ops _prop_number_rb_tree_ops = {
@ -141,7 +168,14 @@ _prop_number_externalize(struct _prop_object_externalize_context *ctx,
prop_number_t pn = v;
char tmpstr[32];
sprintf(tmpstr, "0x%" PRIx64, pn->pn_number);
/*
* For unsigned numbers, we output in hex. For signed numbers,
* we output in decimal.
*/
if (pn->pn_value.pnv_is_unsigned)
sprintf(tmpstr, "0x%" PRIx64, pn->pn_value.pnv_unsigned);
else
sprintf(tmpstr, "%" PRIi64, pn->pn_value.pnv_signed);
if (_prop_object_externalize_start_tag(ctx, "integer") == FALSE ||
_prop_object_externalize_append_cstring(ctx, tmpstr) == FALSE ||
@ -163,13 +197,50 @@ _prop_number_equals(void *v1, void *v2)
/*
* There is only ever one copy of a number object at any given
* time, so we can reduce this to a simple pointer equality check.
* time, so we can reduce this to a simple pointer equality check
* in the common case.
*/
return (num1 == num2);
if (num1 == num2)
return (TRUE);
/*
* If the numbers are the same signed-ness, then we know they
* cannot be equal because they would have had pointer equality.
*/
if (num1->pn_value.pnv_is_unsigned == num2->pn_value.pnv_is_unsigned)
return (FALSE);
/*
* We now have one signed value and one unsigned value. We can
* compare them iff:
* - The unsigned value is not larger than the signed value
* can represent.
* - The signed value is not smaller than the unsigned value
* can represent.
*/
if (num1->pn_value.pnv_is_unsigned) {
/*
* num1 is unsigned and num2 is signed.
*/
if (num1->pn_value.pnv_unsigned > INT64_MAX)
return (FALSE);
if (num2->pn_value.pnv_signed < 0)
return (FALSE);
} else {
/*
* num1 is signed and num2 is unsigned.
*/
if (num1->pn_value.pnv_signed < 0)
return (FALSE);
if (num2->pn_value.pnv_unsigned > INT64_MAX)
return (FALSE);
}
return (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed);
}
static prop_number_t
_prop_number_alloc(uint64_t val)
_prop_number_alloc(const struct _prop_number_value *pnv)
{
prop_number_t opn, pn;
struct rb_node *n;
@ -184,7 +255,7 @@ _prop_number_alloc(uint64_t val)
&_prop_number_rb_tree_ops);
_prop_number_tree_initialized = TRUE;
} else {
n = _prop_rb_tree_find(&_prop_number_tree, &val);
n = _prop_rb_tree_find(&_prop_number_tree, pnv);
if (n != NULL) {
opn = RBNODE_TO_PN(n);
prop_object_retain(opn);
@ -204,14 +275,14 @@ _prop_number_alloc(uint64_t val)
_prop_object_init(&pn->pn_obj, &_prop_object_type_number);
pn->pn_number = val;
pn->pn_value = *pnv;
/*
* We dropped the mutex when we allocated the new object, so
* we have to check again if it is in the tree.
*/
_PROP_MUTEX_LOCK(_prop_number_tree_mutex);
n = _prop_rb_tree_find(&_prop_number_tree, &val);
n = _prop_rb_tree_find(&_prop_number_tree, pnv);
if (n != NULL) {
opn = RBNODE_TO_PN(n);
prop_object_retain(opn);
@ -230,10 +301,30 @@ _prop_number_alloc(uint64_t val)
* provided integer value.
*/
prop_number_t
prop_number_create_integer(uint64_t val)
prop_number_create_integer(int64_t val)
{
const struct _prop_number_value pnv = {
.pnv_signed = val,
.pnv_is_unsigned = FALSE,
};
return (_prop_number_alloc(val));
return (_prop_number_alloc(&pnv));
}
/*
* prop_number_create_unsigned_integer --
* Create a prop_number_t and initialize it with the
* provided unsigned integer value.
*/
prop_number_t
prop_number_create_unsigned_integer(uint64_t val)
{
const struct _prop_number_value pnv = {
.pnv_unsigned = val,
.pnv_is_unsigned = TRUE,
};
return (_prop_number_alloc(&pnv));
}
/*
@ -255,6 +346,17 @@ prop_number_copy(prop_number_t opn)
return (opn);
}
/*
* prop_number_unsigned --
* Returns TRUE if the prop_number_t has an unsigned value.
*/
boolean_t
prop_number_unsigned(prop_number_t pn)
{
return (pn->pn_value.pnv_is_unsigned);
}
/*
* prop_number_size --
* Return the size, in bits, required to hold the value of
@ -263,15 +365,28 @@ prop_number_copy(prop_number_t opn)
int
prop_number_size(prop_number_t pn)
{
struct _prop_number_value *pnv;
if (! prop_object_is_number(pn))
return (0);
if (pn->pn_number > UINT32_MAX)
return (64);
if (pn->pn_number > UINT16_MAX)
pnv = &pn->pn_value;
if (pnv->pnv_is_unsigned) {
if (pnv->pnv_unsigned > UINT32_MAX)
return (64);
if (pnv->pnv_unsigned > UINT16_MAX)
return (32);
if (pnv->pnv_unsigned > UINT8_MAX)
return (16);
return (8);
}
if (pnv->pnv_signed > INT32_MAX || pnv->pnv_signed < INT32_MIN)
return (64);
if (pnv->pnv_signed > INT16_MAX || pnv->pnv_signed < INT16_MIN)
return (32);
if (pn->pn_number > UINT8_MAX)
if (pnv->pnv_signed > INT8_MAX || pnv->pnv_signed < INT8_MIN)
return (16);
return (8);
}
@ -280,7 +395,7 @@ prop_number_size(prop_number_t pn)
* prop_number_integer_value --
* Get the integer value of a prop_number_t.
*/
uint64_t
int64_t
prop_number_integer_value(prop_number_t pn)
{
@ -291,7 +406,25 @@ prop_number_integer_value(prop_number_t pn)
if (! prop_object_is_number(pn))
return (0);
return (pn->pn_number);
return (pn->pn_value.pnv_signed);
}
/*
* prop_number_unsigned_integer_value --
* Get the unsigned integer value of a prop_number_t.
*/
uint64_t
prop_number_unsigned_integer_value(prop_number_t pn)
{
/*
* XXX Impossible to distinguish between "not a prop_number_t"
* XXX and "prop_number_t has a value of 0".
*/
if (! prop_object_is_number(pn))
return (0);
return (pn->pn_value.pnv_unsigned);
}
/*
@ -310,13 +443,81 @@ prop_number_equals(prop_number_t num1, prop_number_t num2)
* Return TRUE if the number is equivalent to the specified integer.
*/
boolean_t
prop_number_equals_integer(prop_number_t pn, uint64_t val)
prop_number_equals_integer(prop_number_t pn, int64_t val)
{
if (! prop_object_is_number(pn))
return (FALSE);
return (pn->pn_number == val);
if (pn->pn_value.pnv_is_unsigned &&
(pn->pn_value.pnv_unsigned > INT64_MAX || val < 0))
return (FALSE);
return (pn->pn_value.pnv_signed == val);
}
/*
* prop_number_equals_unsigned_integer --
* Return TRUE if the number is equivalent to the specified
* unsigned integer.
*/
boolean_t
prop_number_equals_unsigned_integer(prop_number_t pn, uint64_t val)
{
if (! prop_object_is_number(pn))
return (FALSE);
if (! pn->pn_value.pnv_is_unsigned &&
(pn->pn_value.pnv_signed < 0 || val > INT64_MAX))
return (FALSE);
return (pn->pn_value.pnv_unsigned == val);
}
static boolean_t
_prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx,
struct _prop_number_value *pnv)
{
char *cp;
_PROP_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t));
#ifndef _KERNEL
errno = 0;
#endif
pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0);
#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE)
return (FALSE);
#endif
pnv->pnv_is_unsigned = TRUE;
ctx->poic_cp = cp;
return (TRUE);
}
static boolean_t
_prop_number_internalize_signed(struct _prop_object_internalize_context *ctx,
struct _prop_number_value *pnv)
{
char *cp;
_PROP_ASSERT(sizeof(long long) == sizeof(int64_t));
#ifndef _KERNEL
errno = 0;
#endif
pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0);
#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) &&
errno == ERANGE)
return (FALSE);
#endif
pnv->pnv_is_unsigned = FALSE;
ctx->poic_cp = cp;
return (TRUE);
}
/*
@ -327,26 +528,37 @@ prop_number_equals_integer(prop_number_t pn, uint64_t val)
prop_object_t
_prop_number_internalize(struct _prop_object_internalize_context *ctx)
{
uint64_t val = 0;
char *cp;
struct _prop_number_value pnv = {
.pnv_unsigned = 0,
.pnv_is_unsigned = FALSE,
};
/* No attributes, no empty elements. */
if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element)
return (NULL);
#ifndef _KERNEL
errno = 0;
#endif
val = strtoumax(ctx->poic_cp, &cp, 0);
#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
if (val == UINTMAX_MAX && errno == ERANGE)
return (NULL);
#endif
ctx->poic_cp = cp;
/*
* If the first character is '-', then we treat as signed.
* If the first two characters are "0x" (i.e. the number is
* in hex), then we treat as unsigned. Otherwise, we try
* signed first, and if that fails (presumably due to ERANGE),
* then we switch to unsigned.
*/
if (ctx->poic_cp[0] == '-') {
if (_prop_number_internalize_signed(ctx, &pnv) == FALSE)
return (NULL);
} else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') {
if (_prop_number_internalize_unsigned(ctx, &pnv) == FALSE)
return (NULL);
} else {
if (_prop_number_internalize_signed(ctx, &pnv) == FALSE &&
_prop_number_internalize_unsigned(ctx, &pnv) == FALSE)
return (NULL);
}
if (_prop_object_internalize_find_tag(ctx, "integer",
_PROP_TAG_TYPE_END) == FALSE)
return (NULL);
return (_prop_number_alloc(val));
return (_prop_number_alloc(&pnv));
}

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.942 2006/10/09 19:33:22 ghen Exp $
# $NetBSD: mi,v 1.943 2006/10/12 04:46:57 thorpej Exp $
./etc/mtree/set.comp comp-sys-root
./usr/bin/addr2line comp-debug-bin bfd
./usr/bin/ar comp-util-bin bfd
@ -5449,9 +5449,12 @@
./usr/share/man/cat3/prop_number.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_copy.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_create_integer.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_create_unsigned_integer.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_equals.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_equals_integer.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_equals_unsigned_integer.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_integer_value.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_unsigned.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_unsigned_integer_value.0 comp-c-catman .cat
./usr/share/man/cat3/prop_number_size.0 comp-c-catman .cat
./usr/share/man/cat3/prop_object.0 comp-c-catman .cat
./usr/share/man/cat3/prop_object_equals.0 comp-c-catman .cat
@ -9651,9 +9654,13 @@
./usr/share/man/man3/prop_number.3 comp-c-man .man
./usr/share/man/man3/prop_number_copy.3 comp-c-man .man
./usr/share/man/man3/prop_number_create_integer.3 comp-c-man .man
./usr/share/man/man3/prop_number_create_unsigned_integer.3 comp-c-man .man
./usr/share/man/man3/prop_number_equals.3 comp-c-man .man
./usr/share/man/man3/prop_number_equals_integer.3 comp-c-man .man
./usr/share/man/man3/prop_number_equals_unsigned_integer.3 comp-c-man .man
./usr/share/man/man3/prop_number_integer_value.3 comp-c-man .man
./usr/share/man/man3/prop_number_unsigned.3 comp-c-man .man
./usr/share/man/man3/prop_number_unsigned_integer_value.3 comp-c-man .man
./usr/share/man/man3/prop_number_size.3 comp-c-man .man
./usr/share/man/man3/prop_object.3 comp-c-man .man
./usr/share/man/man3/prop_object_equals.3 comp-c-man .man

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.7 2006/09/22 04:20:23 thorpej Exp $
# $NetBSD: Makefile,v 1.8 2006/10/12 04:46:56 thorpej Exp $
.include <bsd.own.mk>
@ -90,10 +90,14 @@ MLINKS+= prop_ingest.3 prop_dictionary_ingest.3
MLINKS+= prop_number.3 prop_number_copy.3
MLINKS+= prop_number.3 prop_number_create_integer.3
MLINKS+= prop_number.3 prop_number_create_unsigned_integer.3
MLINKS+= prop_number.3 prop_number_equals.3
MLINKS+= prop_number.3 prop_number_equals_integer.3
MLINKS+= prop_number.3 prop_number_equals_unsigned_integer.3
MLINKS+= prop_number.3 prop_number_size.3
MLINKS+= prop_number.3 prop_number_unsigned.3
MLINKS+= prop_number.3 prop_number_integer_value.3
MLINKS+= prop_number.3 prop_number_unsigned_integer_value.3
MLINKS+= prop_object.3 prop_object_equals.3
MLINKS+= prop_object.3 prop_object_iterator_next.3