http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/message.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/message.c b/proton-c/src/core/message.c new file mode 100644 index 0000000..f2fb20e --- /dev/null +++ b/proton-c/src/core/message.c @@ -0,0 +1,862 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "platform/platform_fmt.h" +#include "protocol.h" +#include "util.h" + +#include <proton/message.h> +#include <proton/object.h> +#include <proton/codec.h> +#include <proton/error.h> +#include <proton/parser.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> + +// message + +struct pn_message_t { + pn_timestamp_t expiry_time; + pn_timestamp_t creation_time; + pn_data_t *id; + pn_string_t *user_id; + pn_string_t *address; + pn_string_t *subject; + pn_string_t *reply_to; + pn_data_t *correlation_id; + pn_string_t *content_type; + pn_string_t *content_encoding; + pn_string_t *group_id; + pn_string_t *reply_to_group_id; + + pn_data_t *data; + pn_data_t *instructions; + pn_data_t *annotations; + pn_data_t *properties; + pn_data_t *body; + + pn_error_t *error; + + pn_sequence_t group_sequence; + pn_millis_t ttl; + uint32_t delivery_count; + + uint8_t priority; + + bool durable; + bool first_acquirer; + bool inferred; +}; + +void pn_message_finalize(void *obj) +{ + pn_message_t *msg = (pn_message_t *) obj; + pn_free(msg->user_id); + pn_free(msg->address); + pn_free(msg->subject); + pn_free(msg->reply_to); + pn_free(msg->content_type); + pn_free(msg->content_encoding); + pn_free(msg->group_id); + pn_free(msg->reply_to_group_id); + pn_data_free(msg->id); + pn_data_free(msg->correlation_id); + pn_data_free(msg->data); + pn_data_free(msg->instructions); + pn_data_free(msg->annotations); + pn_data_free(msg->properties); + pn_data_free(msg->body); + pn_error_free(msg->error); +} + +int pn_message_inspect(void *obj, pn_string_t *dst) +{ + pn_message_t *msg = (pn_message_t *) obj; + int err = pn_string_addf(dst, "Message{"); + if (err) return err; + + bool comma = false; + + if (pn_string_get(msg->address)) { + err = pn_string_addf(dst, "address="); + if (err) return err; + err = pn_inspect(msg->address, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (msg->durable) { + err = pn_string_addf(dst, "durable=%i, ", msg->durable); + if (err) return err; + comma = true; + } + + if (msg->priority != PN_DEFAULT_PRIORITY) { + err = pn_string_addf(dst, "priority=%i, ", msg->priority); + if (err) return err; + comma = true; + } + + if (msg->ttl) { + err = pn_string_addf(dst, "ttl=%" PRIu32 ", ", msg->ttl); + if (err) return err; + comma = true; + } + + if (msg->first_acquirer) { + err = pn_string_addf(dst, "first_acquirer=%i, ", msg->first_acquirer); + if (err) return err; + comma = true; + } + + if (msg->delivery_count) { + err = pn_string_addf(dst, "delivery_count=%" PRIu32 ", ", msg->delivery_count); + if (err) return err; + comma = true; + } + + if (pn_data_size(msg->id)) { + err = pn_string_addf(dst, "id="); + if (err) return err; + err = pn_inspect(msg->id, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->user_id)) { + err = pn_string_addf(dst, "user_id="); + if (err) return err; + err = pn_inspect(msg->user_id, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->subject)) { + err = pn_string_addf(dst, "subject="); + if (err) return err; + err = pn_inspect(msg->subject, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->reply_to)) { + err = pn_string_addf(dst, "reply_to="); + if (err) return err; + err = pn_inspect(msg->reply_to, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_data_size(msg->correlation_id)) { + err = pn_string_addf(dst, "correlation_id="); + if (err) return err; + err = pn_inspect(msg->correlation_id, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->content_type)) { + err = pn_string_addf(dst, "content_type="); + if (err) return err; + err = pn_inspect(msg->content_type, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->content_encoding)) { + err = pn_string_addf(dst, "content_encoding="); + if (err) return err; + err = pn_inspect(msg->content_encoding, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (msg->expiry_time) { + err = pn_string_addf(dst, "expiry_time=%" PRIi64 ", ", msg->expiry_time); + if (err) return err; + comma = true; + } + + if (msg->creation_time) { + err = pn_string_addf(dst, "creation_time=%" PRIi64 ", ", msg->creation_time); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->group_id)) { + err = pn_string_addf(dst, "group_id="); + if (err) return err; + err = pn_inspect(msg->group_id, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (msg->group_sequence) { + err = pn_string_addf(dst, "group_sequence=%" PRIi32 ", ", msg->group_sequence); + if (err) return err; + comma = true; + } + + if (pn_string_get(msg->reply_to_group_id)) { + err = pn_string_addf(dst, "reply_to_group_id="); + if (err) return err; + err = pn_inspect(msg->reply_to_group_id, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (msg->inferred) { + err = pn_string_addf(dst, "inferred=%i, ", msg->inferred); + if (err) return err; + comma = true; + } + + if (pn_data_size(msg->instructions)) { + err = pn_string_addf(dst, "instructions="); + if (err) return err; + err = pn_inspect(msg->instructions, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_data_size(msg->annotations)) { + err = pn_string_addf(dst, "annotations="); + if (err) return err; + err = pn_inspect(msg->annotations, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_data_size(msg->properties)) { + err = pn_string_addf(dst, "properties="); + if (err) return err; + err = pn_inspect(msg->properties, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (pn_data_size(msg->body)) { + err = pn_string_addf(dst, "body="); + if (err) return err; + err = pn_inspect(msg->body, dst); + if (err) return err; + err = pn_string_addf(dst, ", "); + if (err) return err; + comma = true; + } + + if (comma) { + int err = pn_string_resize(dst, pn_string_size(dst) - 2); + if (err) return err; + } + + return pn_string_addf(dst, "}"); +} + +#define pn_message_initialize NULL +#define pn_message_hashcode NULL +#define pn_message_compare NULL + +pn_message_t *pn_message() +{ + static const pn_class_t clazz = PN_CLASS(pn_message); + pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, sizeof(pn_message_t)); + msg->durable = false; + msg->priority = PN_DEFAULT_PRIORITY; + msg->ttl = 0; + msg->first_acquirer = false; + msg->delivery_count = 0; + msg->id = pn_data(1); + msg->user_id = pn_string(NULL); + msg->address = pn_string(NULL); + msg->subject = pn_string(NULL); + msg->reply_to = pn_string(NULL); + msg->correlation_id = pn_data(1); + msg->content_type = pn_string(NULL); + msg->content_encoding = pn_string(NULL); + msg->expiry_time = 0; + msg->creation_time = 0; + msg->group_id = pn_string(NULL); + msg->group_sequence = 0; + msg->reply_to_group_id = pn_string(NULL); + + msg->inferred = false; + msg->data = pn_data(16); + msg->instructions = pn_data(16); + msg->annotations = pn_data(16); + msg->properties = pn_data(16); + msg->body = pn_data(16); + + msg->error = pn_error(); + return msg; +} + +void pn_message_free(pn_message_t *msg) +{ + pn_free(msg); +} + +void pn_message_clear(pn_message_t *msg) +{ + msg->durable = false; + msg->priority = PN_DEFAULT_PRIORITY; + msg->ttl = 0; + msg->first_acquirer = false; + msg->delivery_count = 0; + pn_data_clear(msg->id); + pn_string_clear(msg->user_id); + pn_string_clear(msg->address); + pn_string_clear(msg->subject); + pn_string_clear(msg->reply_to); + pn_data_clear(msg->correlation_id); + pn_string_clear(msg->content_type); + pn_string_clear(msg->content_encoding); + msg->expiry_time = 0; + msg->creation_time = 0; + pn_string_clear(msg->group_id); + msg->group_sequence = 0; + pn_string_clear(msg->reply_to_group_id); + msg->inferred = false; + pn_data_clear(msg->data); + pn_data_clear(msg->instructions); + pn_data_clear(msg->annotations); + pn_data_clear(msg->properties); + pn_data_clear(msg->body); +} + +int pn_message_errno(pn_message_t *msg) +{ + assert(msg); + return pn_error_code(msg->error); +} + +pn_error_t *pn_message_error(pn_message_t *msg) +{ + assert(msg); + return msg->error; +} + +bool pn_message_is_inferred(pn_message_t *msg) +{ + assert(msg); + return msg->inferred; +} + +int pn_message_set_inferred(pn_message_t *msg, bool inferred) +{ + assert(msg); + msg->inferred = inferred; + return 0; +} + +bool pn_message_is_durable(pn_message_t *msg) +{ + assert(msg); + return msg->durable; +} +int pn_message_set_durable(pn_message_t *msg, bool durable) +{ + assert(msg); + msg->durable = durable; + return 0; +} + + +uint8_t pn_message_get_priority(pn_message_t *msg) +{ + assert(msg); + return msg->priority; +} +int pn_message_set_priority(pn_message_t *msg, uint8_t priority) +{ + assert(msg); + msg->priority = priority; + return 0; +} + +pn_millis_t pn_message_get_ttl(pn_message_t *msg) +{ + assert(msg); + return msg->ttl; +} +int pn_message_set_ttl(pn_message_t *msg, pn_millis_t ttl) +{ + assert(msg); + msg->ttl = ttl; + return 0; +} + +bool pn_message_is_first_acquirer(pn_message_t *msg) +{ + assert(msg); + return msg->first_acquirer; +} +int pn_message_set_first_acquirer(pn_message_t *msg, bool first) +{ + assert(msg); + msg->first_acquirer = first; + return 0; +} + +uint32_t pn_message_get_delivery_count(pn_message_t *msg) +{ + assert(msg); + return msg->delivery_count; +} +int pn_message_set_delivery_count(pn_message_t *msg, uint32_t count) +{ + assert(msg); + msg->delivery_count = count; + return 0; +} + +pn_data_t *pn_message_id(pn_message_t *msg) +{ + assert(msg); + return msg->id; +} +pn_atom_t pn_message_get_id(pn_message_t *msg) +{ + assert(msg); + return pn_data_get_atom(msg->id); +} +int pn_message_set_id(pn_message_t *msg, pn_atom_t id) +{ + assert(msg); + pn_data_rewind(msg->id); + return pn_data_put_atom(msg->id, id); +} + +static pn_bytes_t pn_string_get_bytes(pn_string_t *string) +{ + return pn_bytes(pn_string_size(string), (char *) pn_string_get(string)); +} + +static int pn_string_set_bytes(pn_string_t *string, pn_bytes_t bytes) +{ + return pn_string_setn(string, bytes.start, bytes.size); +} + +pn_bytes_t pn_message_get_user_id(pn_message_t *msg) +{ + assert(msg); + return pn_string_get_bytes(msg->user_id); +} +int pn_message_set_user_id(pn_message_t *msg, pn_bytes_t user_id) +{ + assert(msg); + return pn_string_set_bytes(msg->user_id, user_id); +} + +const char *pn_message_get_address(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->address); +} +int pn_message_set_address(pn_message_t *msg, const char *address) +{ + assert(msg); + return pn_string_set(msg->address, address); +} + +const char *pn_message_get_subject(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->subject); +} +int pn_message_set_subject(pn_message_t *msg, const char *subject) +{ + assert(msg); + return pn_string_set(msg->subject, subject); +} + +const char *pn_message_get_reply_to(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->reply_to); +} +int pn_message_set_reply_to(pn_message_t *msg, const char *reply_to) +{ + assert(msg); + return pn_string_set(msg->reply_to, reply_to); +} + +pn_data_t *pn_message_correlation_id(pn_message_t *msg) +{ + assert(msg); + return msg->correlation_id; +} +pn_atom_t pn_message_get_correlation_id(pn_message_t *msg) +{ + assert(msg); + return pn_data_get_atom(msg->correlation_id); +} +int pn_message_set_correlation_id(pn_message_t *msg, pn_atom_t atom) +{ + assert(msg); + pn_data_rewind(msg->correlation_id); + return pn_data_put_atom(msg->correlation_id, atom); +} + +const char *pn_message_get_content_type(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->content_type); +} +int pn_message_set_content_type(pn_message_t *msg, const char *type) +{ + assert(msg); + return pn_string_set(msg->content_type, type); +} + +const char *pn_message_get_content_encoding(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->content_encoding); +} +int pn_message_set_content_encoding(pn_message_t *msg, const char *encoding) +{ + assert(msg); + return pn_string_set(msg->content_encoding, encoding); +} + +pn_timestamp_t pn_message_get_expiry_time(pn_message_t *msg) +{ + assert(msg); + return msg->expiry_time; +} +int pn_message_set_expiry_time(pn_message_t *msg, pn_timestamp_t time) +{ + assert(msg); + msg->expiry_time = time; + return 0; +} + +pn_timestamp_t pn_message_get_creation_time(pn_message_t *msg) +{ + assert(msg); + return msg->creation_time; +} +int pn_message_set_creation_time(pn_message_t *msg, pn_timestamp_t time) +{ + assert(msg); + msg->creation_time = time; + return 0; +} + +const char *pn_message_get_group_id(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->group_id); +} +int pn_message_set_group_id(pn_message_t *msg, const char *group_id) +{ + assert(msg); + return pn_string_set(msg->group_id, group_id); +} + +pn_sequence_t pn_message_get_group_sequence(pn_message_t *msg) +{ + assert(msg); + return msg->group_sequence; +} +int pn_message_set_group_sequence(pn_message_t *msg, pn_sequence_t n) +{ + assert(msg); + msg->group_sequence = n; + return 0; +} + +const char *pn_message_get_reply_to_group_id(pn_message_t *msg) +{ + assert(msg); + return pn_string_get(msg->reply_to_group_id); +} +int pn_message_set_reply_to_group_id(pn_message_t *msg, const char *reply_to_group_id) +{ + assert(msg); + return pn_string_set(msg->reply_to_group_id, reply_to_group_id); +} + +int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size) +{ + assert(msg && bytes && size); + + pn_message_clear(msg); + + while (size) { + pn_data_clear(msg->data); + ssize_t used = pn_data_decode(msg->data, bytes, size); + if (used < 0) + return pn_error_format(msg->error, used, "data error: %s", + pn_error_text(pn_data_error(msg->data))); + size -= used; + bytes += used; + bool scanned; + uint64_t desc; + int err = pn_data_scan(msg->data, "D?L.", &scanned, &desc); + if (err) return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(msg->data))); + if (!scanned) { + desc = 0; + } + + pn_data_rewind(msg->data); + pn_data_next(msg->data); + pn_data_enter(msg->data); + pn_data_next(msg->data); + + switch (desc) { + case HEADER: + err = pn_data_scan(msg->data, "D.[oBIoI]", &msg->durable, &msg->priority, + &msg->ttl, &msg->first_acquirer, &msg->delivery_count); + if (err) return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(msg->data))); + break; + case PROPERTIES: + { + pn_bytes_t user_id, address, subject, reply_to, ctype, cencoding, + group_id, reply_to_group_id; + pn_data_clear(msg->id); + pn_data_clear(msg->correlation_id); + err = pn_data_scan(msg->data, "D.[CzSSSCssttSIS]", msg->id, + &user_id, &address, &subject, &reply_to, + msg->correlation_id, &ctype, &cencoding, + &msg->expiry_time, &msg->creation_time, &group_id, + &msg->group_sequence, &reply_to_group_id); + if (err) return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(msg->data))); + err = pn_string_set_bytes(msg->user_id, user_id); + if (err) return pn_error_format(msg->error, err, "error setting user_id"); + err = pn_string_setn(msg->address, address.start, address.size); + if (err) return pn_error_format(msg->error, err, "error setting address"); + err = pn_string_setn(msg->subject, subject.start, subject.size); + if (err) return pn_error_format(msg->error, err, "error setting subject"); + err = pn_string_setn(msg->reply_to, reply_to.start, reply_to.size); + if (err) return pn_error_format(msg->error, err, "error setting reply_to"); + err = pn_string_setn(msg->content_type, ctype.start, ctype.size); + if (err) return pn_error_format(msg->error, err, "error setting content_type"); + err = pn_string_setn(msg->content_encoding, cencoding.start, + cencoding.size); + if (err) return pn_error_format(msg->error, err, "error setting content_encoding"); + err = pn_string_setn(msg->group_id, group_id.start, group_id.size); + if (err) return pn_error_format(msg->error, err, "error setting group_id"); + err = pn_string_setn(msg->reply_to_group_id, reply_to_group_id.start, + reply_to_group_id.size); + if (err) return pn_error_format(msg->error, err, "error setting reply_to_group_id"); + } + break; + case DELIVERY_ANNOTATIONS: + pn_data_narrow(msg->data); + err = pn_data_copy(msg->instructions, msg->data); + if (err) return err; + break; + case MESSAGE_ANNOTATIONS: + pn_data_narrow(msg->data); + err = pn_data_copy(msg->annotations, msg->data); + if (err) return err; + break; + case APPLICATION_PROPERTIES: + pn_data_narrow(msg->data); + err = pn_data_copy(msg->properties, msg->data); + if (err) return err; + break; + case DATA: + case AMQP_SEQUENCE: + case AMQP_VALUE: + pn_data_narrow(msg->data); + err = pn_data_copy(msg->body, msg->data); + if (err) return err; + break; + case FOOTER: + break; + default: + err = pn_data_copy(msg->body, msg->data); + if (err) return err; + break; + } + } + + pn_data_clear(msg->data); + return 0; +} + +int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size) +{ + if (!msg || !bytes || !size || !*size) return PN_ARG_ERR; + pn_data_clear(msg->data); + pn_message_data(msg, msg->data); + size_t remaining = *size; + ssize_t encoded = pn_data_encode(msg->data, bytes, remaining); + if (encoded < 0) { + if (encoded == PN_OVERFLOW) { + return encoded; + } else { + return pn_error_format(msg->error, encoded, "data error: %s", + pn_error_text(pn_data_error(msg->data))); + } + } + bytes += encoded; + remaining -= encoded; + *size -= remaining; + pn_data_clear(msg->data); + return 0; +} + +int pn_message_data(pn_message_t *msg, pn_data_t *data) +{ + pn_data_clear(data); + int err = pn_data_fill(data, "DL[oB?IoI]", HEADER, msg->durable, + msg->priority, msg->ttl, msg->ttl, msg->first_acquirer, + msg->delivery_count); + if (err) + return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(data))); + + if (pn_data_size(msg->instructions)) { + pn_data_put_described(data); + pn_data_enter(data); + pn_data_put_ulong(data, DELIVERY_ANNOTATIONS); + pn_data_rewind(msg->instructions); + err = pn_data_append(data, msg->instructions); + if (err) + return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(data))); + pn_data_exit(data); + } + + if (pn_data_size(msg->annotations)) { + pn_data_put_described(data); + pn_data_enter(data); + pn_data_put_ulong(data, MESSAGE_ANNOTATIONS); + pn_data_rewind(msg->annotations); + err = pn_data_append(data, msg->annotations); + if (err) + return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(data))); + pn_data_exit(data); + } + + err = pn_data_fill(data, "DL[CzSSSCssttSIS]", PROPERTIES, + msg->id, + pn_string_size(msg->user_id), pn_string_get(msg->user_id), + pn_string_get(msg->address), + pn_string_get(msg->subject), + pn_string_get(msg->reply_to), + msg->correlation_id, + pn_string_get(msg->content_type), + pn_string_get(msg->content_encoding), + msg->expiry_time, + msg->creation_time, + pn_string_get(msg->group_id), + msg->group_sequence, + pn_string_get(msg->reply_to_group_id)); + if (err) + return pn_error_format(msg->error, err, "data error: %s", + pn_error_text(pn_data_error(data))); + + if (pn_data_size(msg->properties)) { + pn_data_put_described(data); + pn_data_enter(data); + pn_data_put_ulong(data, APPLICATION_PROPERTIES); + pn_data_rewind(msg->properties); + err = pn_data_append(data, msg->properties); + if (err) + return pn_error_format(msg->error, err, "data error: %s", + pn_data_error(data)); + pn_data_exit(data); + } + + if (pn_data_size(msg->body)) { + pn_data_rewind(msg->body); + pn_data_next(msg->body); + pn_type_t body_type = pn_data_type(msg->body); + pn_data_rewind(msg->body); + + pn_data_put_described(data); + pn_data_enter(data); + if (msg->inferred) { + switch (body_type) { + case PN_BINARY: + pn_data_put_ulong(data, DATA); + break; + case PN_LIST: + pn_data_put_ulong(data, AMQP_SEQUENCE); + break; + default: + pn_data_put_ulong(data, AMQP_VALUE); + break; + } + } else { + pn_data_put_ulong(data, AMQP_VALUE); + } + pn_data_append(data, msg->body); + } + return 0; +} + +pn_data_t *pn_message_instructions(pn_message_t *msg) +{ + return msg ? msg->instructions : NULL; +} + +pn_data_t *pn_message_annotations(pn_message_t *msg) +{ + return msg ? msg->annotations : NULL; +} + +pn_data_t *pn_message_properties(pn_message_t *msg) +{ + return msg ? msg->properties : NULL; +} + +pn_data_t *pn_message_body(pn_message_t *msg) +{ + return msg ? msg->body : NULL; +}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/iterator.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/object/iterator.c b/proton-c/src/core/object/iterator.c new file mode 100644 index 0000000..61b3b8e --- /dev/null +++ b/proton-c/src/core/object/iterator.c @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <proton/object.h> +#include <stdlib.h> +#include <assert.h> + +struct pn_iterator_t { + pn_iterator_next_t next; + size_t size; + void *state; +}; + +static void pn_iterator_initialize(void *object) +{ + pn_iterator_t *it = (pn_iterator_t *) object; + it->next = NULL; + it->size = 0; + it->state = NULL; +} + +static void pn_iterator_finalize(void *object) +{ + pn_iterator_t *it = (pn_iterator_t *) object; + free(it->state); +} + +#define CID_pn_iterator CID_pn_object +#define pn_iterator_hashcode NULL +#define pn_iterator_compare NULL +#define pn_iterator_inspect NULL + +pn_iterator_t *pn_iterator() +{ + static const pn_class_t clazz = PN_CLASS(pn_iterator); + pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t)); + return it; +} + +void *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next, + size_t size) { + assert(iterator); + assert(next); + iterator->next = next; + if (iterator->size < size) { + iterator->state = realloc(iterator->state, size); + } + return iterator->state; +} + +void *pn_iterator_next(pn_iterator_t *iterator) { + assert(iterator); + if (iterator->next) { + void *result = iterator->next(iterator->state); + if (!result) iterator->next = NULL; + return result; + } else { + return NULL; + } +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/list.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/object/list.c b/proton-c/src/core/object/list.c new file mode 100644 index 0000000..76c70d2 --- /dev/null +++ b/proton-c/src/core/object/list.c @@ -0,0 +1,267 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <proton/object.h> +#include <stdlib.h> +#include <assert.h> + +struct pn_list_t { + const pn_class_t *clazz; + size_t capacity; + size_t size; + void **elements; +}; + +size_t pn_list_size(pn_list_t *list) +{ + assert(list); + return list->size; +} + +void *pn_list_get(pn_list_t *list, int index) +{ + assert(list); assert(list->size); + return list->elements[index % list->size]; +} + +void pn_list_set(pn_list_t *list, int index, void *value) +{ + assert(list); assert(list->size); + void *old = list->elements[index % list->size]; + pn_class_decref(list->clazz, old); + list->elements[index % list->size] = value; + pn_class_incref(list->clazz, value); +} + +static void pni_list_ensure(pn_list_t *list, size_t capacity) +{ + assert(list); + if (list->capacity < capacity) { + size_t newcap = list->capacity; + while (newcap < capacity) { newcap *= 2; } + list->elements = (void **) realloc(list->elements, newcap * sizeof(void *)); + assert(list->elements); + list->capacity = newcap; + } +} + +int pn_list_add(pn_list_t *list, void *value) +{ + assert(list); + pni_list_ensure(list, list->size + 1); + list->elements[list->size++] = value; + pn_class_incref(list->clazz, value); + return 0; +} + +void *pn_list_pop(pn_list_t *list) +{ + assert(list); + if (list->size) { + return list->elements[--list->size]; + } else { + return NULL; + } +} + +ssize_t pn_list_index(pn_list_t *list, void *value) +{ + for (size_t i = 0; i < list->size; i++) { + if (pn_class_equals(list->clazz, list->elements[i], value)) { + return i; + } + } + + return -1; +} + +bool pn_list_remove(pn_list_t *list, void *value) +{ + assert(list); + ssize_t idx = pn_list_index(list, value); + if (idx < 0) { + return false; + } else { + pn_list_del(list, idx, 1); + } + + return true; +} + +void pn_list_del(pn_list_t *list, int index, int n) +{ + assert(list); + if (!list->size) { return; } + index %= list->size; + + for (int i = 0; i < n; i++) { + pn_class_decref(list->clazz, list->elements[index + i]); + } + + size_t slide = list->size - (index + n); + for (size_t i = 0; i < slide; i++) { + list->elements[index + i] = list->elements[index + n + i]; + } + + list->size -= n; +} + +void pn_list_clear(pn_list_t *list) +{ + assert(list); + pn_list_del(list, 0, list->size); +} + +void pn_list_minpush(pn_list_t *list, void *value) +{ + assert(list); + pn_list_add(list, value); + // we use one based indexing for the heap + void **heap = list->elements - 1; + int now = list->size; + while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) { + heap[now] = heap[now/2]; + now /= 2; + } + heap[now] = value; +} + +void *pn_list_minpop(pn_list_t *list) +{ + assert(list); + // we use one based indexing for the heap + void **heap = list->elements - 1; + void *min = heap[1]; + void *last = pn_list_pop(list); + int size = pn_list_size(list); + int now, child; + for (now = 1; now*2 <= size; now = child) { + child = now*2; + if (child != size && pn_class_compare(list->clazz, heap[child], heap[child + 1]) > 0) { + child++; + } + if (pn_class_compare(list->clazz, last, heap[child]) > 0) { + heap[now] = heap[child]; + } else { + break; + } + } + heap[now] = last; + return min; +} + +typedef struct { + pn_list_t *list; + size_t index; +} pni_list_iter_t; + +static void *pni_list_next(void *ctx) +{ + pni_list_iter_t *iter = (pni_list_iter_t *) ctx; + if (iter->index < pn_list_size(iter->list)) { + return pn_list_get(iter->list, iter->index++); + } else { + return NULL; + } +} + +void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter) +{ + pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t)); + liter->list = list; + liter->index = 0; +} + +static void pn_list_finalize(void *object) +{ + assert(object); + pn_list_t *list = (pn_list_t *) object; + for (size_t i = 0; i < list->size; i++) { + pn_class_decref(list->clazz, pn_list_get(list, i)); + } + free(list->elements); +} + +static uintptr_t pn_list_hashcode(void *object) +{ + assert(object); + pn_list_t *list = (pn_list_t *) object; + uintptr_t hash = 1; + + for (size_t i = 0; i < list->size; i++) { + hash = hash * 31 + pn_hashcode(pn_list_get(list, i)); + } + + return hash; +} + +static intptr_t pn_list_compare(void *oa, void *ob) +{ + assert(oa); assert(ob); + pn_list_t *a = (pn_list_t *) oa; + pn_list_t *b = (pn_list_t *) ob; + + size_t na = pn_list_size(a); + size_t nb = pn_list_size(b); + if (na != nb) { + return nb - na; + } else { + for (size_t i = 0; i < na; i++) { + intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i)); + if (delta) return delta; + } + } + + return 0; +} + +static int pn_list_inspect(void *obj, pn_string_t *dst) +{ + assert(obj); + pn_list_t *list = (pn_list_t *) obj; + int err = pn_string_addf(dst, "["); + if (err) return err; + size_t n = pn_list_size(list); + for (size_t i = 0; i < n; i++) { + if (i > 0) { + err = pn_string_addf(dst, ", "); + if (err) return err; + } + err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst); + if (err) return err; + } + return pn_string_addf(dst, "]"); +} + +#define pn_list_initialize NULL + +pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity) +{ + static const pn_class_t list_clazz = PN_CLASS(pn_list); + + pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t)); + list->clazz = clazz; + list->capacity = capacity ? capacity : 16; + list->elements = (void **) malloc(list->capacity * sizeof(void *)); + list->size = 0; + return list; +} + http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/map.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/object/map.c b/proton-c/src/core/object/map.c new file mode 100644 index 0000000..cd38f19 --- /dev/null +++ b/proton-c/src/core/object/map.c @@ -0,0 +1,461 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <proton/object.h> +#include <stdlib.h> +#include <assert.h> + +#define PNI_ENTRY_FREE (0) +#define PNI_ENTRY_LINK (1) +#define PNI_ENTRY_TAIL (2) + +typedef struct { + void *key; + void *value; + size_t next; + uint8_t state; +} pni_entry_t; + +struct pn_map_t { + const pn_class_t *key; + const pn_class_t *value; + pni_entry_t *entries; + size_t capacity; + size_t addressable; + size_t size; + uintptr_t (*hashcode)(void *key); + bool (*equals)(void *a, void *b); + float load_factor; +}; + +static void pn_map_finalize(void *object) +{ + pn_map_t *map = (pn_map_t *) object; + + for (size_t i = 0; i < map->capacity; i++) { + if (map->entries[i].state != PNI_ENTRY_FREE) { + pn_class_decref(map->key, map->entries[i].key); + pn_class_decref(map->value, map->entries[i].value); + } + } + + free(map->entries); +} + +static uintptr_t pn_map_hashcode(void *object) +{ + pn_map_t *map = (pn_map_t *) object; + + uintptr_t hashcode = 0; + + for (size_t i = 0; i < map->capacity; i++) { + if (map->entries[i].state != PNI_ENTRY_FREE) { + void *key = map->entries[i].key; + void *value = map->entries[i].value; + hashcode += pn_hashcode(key) ^ pn_hashcode(value); + } + } + + return hashcode; +} + +static void pni_map_allocate(pn_map_t *map) +{ + map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t)); + if (map->entries != NULL) { + for (size_t i = 0; i < map->capacity; i++) { + map->entries[i].key = NULL; + map->entries[i].value = NULL; + map->entries[i].next = 0; + map->entries[i].state = PNI_ENTRY_FREE; + } + } + map->size = 0; +} + +static int pn_map_inspect(void *obj, pn_string_t *dst) +{ + assert(obj); + pn_map_t *map = (pn_map_t *) obj; + int err = pn_string_addf(dst, "{"); + if (err) return err; + pn_handle_t entry = pn_map_head(map); + bool first = true; + while (entry) { + if (first) { + first = false; + } else { + err = pn_string_addf(dst, ", "); + if (err) return err; + } + err = pn_class_inspect(map->key, pn_map_key(map, entry), dst); + if (err) return err; + err = pn_string_addf(dst, ": "); + if (err) return err; + err = pn_class_inspect(map->value, pn_map_value(map, entry), dst); + if (err) return err; + entry = pn_map_next(map, entry); + } + return pn_string_addf(dst, "}"); +} + +#define pn_map_initialize NULL +#define pn_map_compare NULL + +pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value, + size_t capacity, float load_factor) +{ + static const pn_class_t clazz = PN_CLASS(pn_map); + + pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t)); + map->key = key; + map->value = value; + map->capacity = capacity ? capacity : 16; + map->addressable = (size_t) (map->capacity * 0.86); + if (!map->addressable) map->addressable = map->capacity; + map->load_factor = load_factor; + map->hashcode = pn_hashcode; + map->equals = pn_equals; + pni_map_allocate(map); + return map; +} + +size_t pn_map_size(pn_map_t *map) +{ + assert(map); + return map->size; +} + +static float pni_map_load(pn_map_t *map) +{ + return ((float) map->size) / ((float) map->addressable); +} + +static bool pni_map_ensure(pn_map_t *map, size_t capacity) +{ + float load = pni_map_load(map); + if (capacity <= map->capacity && load <= map->load_factor) { + return false; + } + + size_t oldcap = map->capacity; + + while (map->capacity < capacity || pni_map_load(map) > map->load_factor) { + map->capacity *= 2; + map->addressable = (size_t) (0.86 * map->capacity); + } + + pni_entry_t *entries = map->entries; + pni_map_allocate(map); + + for (size_t i = 0; i < oldcap; i++) { + if (entries[i].state != PNI_ENTRY_FREE) { + void *key = entries[i].key; + void *value = entries[i].value; + pn_map_put(map, key, value); + } + } + + for (size_t i = 0; i < oldcap; i++) { + if (entries[i].state != PNI_ENTRY_FREE) { + void *key = entries[i].key; + void *value = entries[i].value; + pn_class_decref(map->key, key); + pn_class_decref(map->value, value); + } + } + + free(entries); + return true; +} + +static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create) +{ + uintptr_t hashcode = map->hashcode(key); + + pni_entry_t *entry = &map->entries[hashcode % map->addressable]; + pni_entry_t *prev = NULL; + + if (entry->state == PNI_ENTRY_FREE) { + if (create) { + entry->state = PNI_ENTRY_TAIL; + entry->key = key; + pn_class_incref(map->key, key); + map->size++; + return entry; + } else { + return NULL; + } + } + + while (true) { + if (map->equals(entry->key, key)) { + if (pprev) *pprev = prev; + return entry; + } + + if (entry->state == PNI_ENTRY_TAIL) { + break; + } else { + prev = entry; + entry = &map->entries[entry->next]; + } + } + + if (create) { + if (pni_map_ensure(map, map->size + 1)) { + // if we had to grow the table we need to start over + return pni_map_entry(map, key, pprev, create); + } + + size_t empty = 0; + for (size_t i = 0; i < map->capacity; i++) { + size_t idx = map->capacity - i - 1; + if (map->entries[idx].state == PNI_ENTRY_FREE) { + empty = idx; + break; + } + } + entry->next = empty; + entry->state = PNI_ENTRY_LINK; + map->entries[empty].state = PNI_ENTRY_TAIL; + map->entries[empty].key = key; + pn_class_incref(map->key, key); + if (pprev) *pprev = entry; + map->size++; + return &map->entries[empty]; + } else { + return NULL; + } +} + +int pn_map_put(pn_map_t *map, void *key, void *value) +{ + assert(map); + pni_entry_t *entry = pni_map_entry(map, key, NULL, true); + void *dref_val = entry->value; + entry->value = value; + pn_class_incref(map->value, value); + pn_class_decref(map->value, dref_val); + return 0; +} + +void *pn_map_get(pn_map_t *map, void *key) +{ + assert(map); + pni_entry_t *entry = pni_map_entry(map, key, NULL, false); + return entry ? entry->value : NULL; +} + +static void pni_map_rehash(pn_map_t *map, size_t index) +{ + //reinsert entries in chain starting at index + assert(map); + size_t i = index; + bool complete = false; + while (!complete) { + pni_entry_t *entry = &map->entries[i]; + assert(entry); + assert(entry->state != PNI_ENTRY_FREE); + size_t current = i; + if (entry->state == PNI_ENTRY_TAIL) { + complete = true; + } else { + assert(entry->state == PNI_ENTRY_LINK); + i = entry->next; + } + uintptr_t hashcode = map->hashcode(entry->key); + pni_entry_t *reloc = &map->entries[hashcode % map->addressable]; + if (reloc->state == PNI_ENTRY_FREE) { + //correct addressable slot is available, copy into that... + reloc->state = PNI_ENTRY_TAIL; + reloc->key = entry->key; + reloc->value = entry->value; + //...then free the current entry + entry->key = NULL; + entry->value = NULL; + entry->state = PNI_ENTRY_FREE; + entry->next = 0; + } else { + //iterate to end of chain... + while (reloc->state == PNI_ENTRY_LINK) { + reloc = &map->entries[reloc->next]; + } + assert(reloc->state == PNI_ENTRY_TAIL); + //... and append current entry + reloc->state = PNI_ENTRY_LINK; + reloc->next = current; + entry->state = PNI_ENTRY_TAIL; + entry->next = 0; + } + } +} + +void pn_map_del(pn_map_t *map, void *key) +{ + assert(map); + pni_entry_t *prev = NULL; + pni_entry_t *entry = pni_map_entry(map, key, &prev, false); + if (entry) { + uint8_t orig_state = entry->state; + size_t orig_next = entry->next; + + void *dref_key = entry->key; + void *dref_value = entry->value; + if (prev) { + prev->next = 0; + prev->state = PNI_ENTRY_TAIL; + } + entry->state = PNI_ENTRY_FREE; + entry->next = 0; + entry->key = NULL; + entry->value = NULL; + map->size--; + + if (orig_state == PNI_ENTRY_LINK) { + pni_map_rehash(map, orig_next); + } + + // do this last as it may trigger further deletions + pn_class_decref(map->key, dref_key); + pn_class_decref(map->value, dref_value); + } +} + +pn_handle_t pn_map_head(pn_map_t *map) +{ + assert(map); + for (size_t i = 0; i < map->capacity; i++) + { + if (map->entries[i].state != PNI_ENTRY_FREE) { + return (pn_handle_t)(i + 1); + } + } + + return 0; +} + +pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry) +{ + for (size_t i = (size_t)entry; i < map->capacity; i++) { + if (map->entries[i].state != PNI_ENTRY_FREE) { + return (pn_handle_t)(i + 1); + } + } + + return 0; +} + +void *pn_map_key(pn_map_t *map, pn_handle_t entry) +{ + assert(map); + assert(entry); + return map->entries[(size_t)entry - 1].key; +} + +void *pn_map_value(pn_map_t *map, pn_handle_t entry) +{ + assert(map); + assert(entry); + return map->entries[(size_t)entry - 1].value; +} + +struct pn_hash_t { + pn_map_t map; +}; + +static uintptr_t pni_identity_hashcode(void *obj) +{ + return (uintptr_t ) obj; +} + +static bool pni_identity_equals(void *a, void *b) +{ + return a == b; +} + +#define CID_pni_uintptr CID_pn_void +static const pn_class_t *pni_uintptr_reify(void *object); +#define pni_uintptr_new NULL +#define pni_uintptr_free NULL +#define pni_uintptr_initialize NULL +static void pni_uintptr_incref(void *object) {} +static void pni_uintptr_decref(void *object) {} +static int pni_uintptr_refcount(void *object) { return -1; } +#define pni_uintptr_finalize NULL +#define pni_uintptr_hashcode NULL +#define pni_uintptr_compare NULL +#define pni_uintptr_inspect NULL + +static const pn_class_t PN_UINTPTR[] = {PN_METACLASS(pni_uintptr)}; + +static const pn_class_t *pni_uintptr_reify(void *object) +{ + return PN_UINTPTR; +} + +pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor) +{ + pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor); + hash->map.hashcode = pni_identity_hashcode; + hash->map.equals = pni_identity_equals; + return hash; +} + +size_t pn_hash_size(pn_hash_t *hash) +{ + return pn_map_size(&hash->map); +} + +int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value) +{ + return pn_map_put(&hash->map, (void *) key, value); +} + +void *pn_hash_get(pn_hash_t *hash, uintptr_t key) +{ + return pn_map_get(&hash->map, (void *) key); +} + +void pn_hash_del(pn_hash_t *hash, uintptr_t key) +{ + pn_map_del(&hash->map, (void *) key); +} + +pn_handle_t pn_hash_head(pn_hash_t *hash) +{ + return pn_map_head(&hash->map); +} + +pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry) +{ + return pn_map_next(&hash->map, entry); +} + +uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry) +{ + return (uintptr_t) pn_map_key(&hash->map, entry); +} + +void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry) +{ + return pn_map_value(&hash->map, entry); +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/object.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/object/object.c b/proton-c/src/core/object/object.c new file mode 100644 index 0000000..b0c1b33 --- /dev/null +++ b/proton-c/src/core/object/object.c @@ -0,0 +1,312 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <proton/object.h> +#include <stdlib.h> +#include <assert.h> + +#define pn_object_initialize NULL +#define pn_object_finalize NULL +#define pn_object_inspect NULL +uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; } +intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; } + +const pn_class_t PN_OBJECT[] = {PN_CLASS(pn_object)}; + +#define pn_void_initialize NULL +static void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); } +static void pn_void_incref(void *object) {} +static void pn_void_decref(void *object) {} +static int pn_void_refcount(void *object) { return -1; } +#define pn_void_finalize NULL +static void pn_void_free(void *object) { free(object); } +static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; } +uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; } +intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; } +int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); } + +const pn_class_t PN_VOID[] = {PN_METACLASS(pn_void)}; + +const char *pn_class_name(const pn_class_t *clazz) +{ + return clazz->name; +} + +pn_cid_t pn_class_id(const pn_class_t *clazz) +{ + return clazz->cid; +} + +void *pn_class_new(const pn_class_t *clazz, size_t size) +{ + assert(clazz); + void *object = clazz->newinst(clazz, size); + if (clazz->initialize) { + clazz->initialize(object); + } + return object; +} + +void *pn_class_incref(const pn_class_t *clazz, void *object) +{ + assert(clazz); + if (object) { + clazz = clazz->reify(object); + clazz->incref(object); + } + return object; +} + +int pn_class_refcount(const pn_class_t *clazz, void *object) +{ + assert(clazz); + clazz = clazz->reify(object); + return clazz->refcount(object); +} + +int pn_class_decref(const pn_class_t *clazz, void *object) +{ + assert(clazz); + + if (object) { + clazz = clazz->reify(object); + clazz->decref(object); + int rc = clazz->refcount(object); + if (rc == 0) { + if (clazz->finalize) { + clazz->finalize(object); + // check the refcount again in case the finalizer created a + // new reference + rc = clazz->refcount(object); + } + if (rc == 0) { + clazz->free(object); + return 0; + } + } else { + return rc; + } + } + + return 0; +} + +void pn_class_free(const pn_class_t *clazz, void *object) +{ + assert(clazz); + if (object) { + clazz = clazz->reify(object); + int rc = clazz->refcount(object); + assert(rc == 1 || rc == -1); + if (rc == 1) { + rc = pn_class_decref(clazz, object); + assert(rc == 0); + } else { + if (clazz->finalize) { + clazz->finalize(object); + } + clazz->free(object); + } + } +} + +const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object) +{ + assert(clazz); + return clazz->reify(object); +} + +uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object) +{ + assert(clazz); + + if (!object) return 0; + + clazz = clazz->reify(object); + + if (clazz->hashcode) { + return clazz->hashcode(object); + } else { + return (uintptr_t) object; + } +} + +intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b) +{ + assert(clazz); + + if (a == b) return 0; + + clazz = clazz->reify(a); + + if (a && b && clazz->compare) { + return clazz->compare(a, b); + } else { + return (intptr_t) a - (intptr_t) b; + } +} + +bool pn_class_equals(const pn_class_t *clazz, void *a, void *b) +{ + return pn_class_compare(clazz, a, b) == 0; +} + +int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst) +{ + assert(clazz); + + clazz = clazz->reify(object); + + if (!pn_string_get(dst)) { + pn_string_set(dst, ""); + } + + if (object && clazz->inspect) { + return clazz->inspect(object, dst); + } + + const char *name = clazz->name ? clazz->name : "<anon>"; + + return pn_string_addf(dst, "%s<%p>", name, object); +} + +typedef struct { + const pn_class_t *clazz; + int refcount; +} pni_head_t; + +#define pni_head(PTR) \ + (((pni_head_t *) (PTR)) - 1) + +void *pn_object_new(const pn_class_t *clazz, size_t size) +{ + void *object = NULL; + pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size); + if (head != NULL) { + object = head + 1; + head->clazz = clazz; + head->refcount = 1; + } + return object; +} + +const pn_class_t *pn_object_reify(void *object) +{ + if (object) { + return pni_head(object)->clazz; + } else { + return PN_OBJECT; + } +} + +void pn_object_incref(void *object) +{ + if (object) { + pni_head(object)->refcount++; + } +} + +int pn_object_refcount(void *object) +{ + assert(object); + return pni_head(object)->refcount; +} + +void pn_object_decref(void *object) +{ + pni_head_t *head = pni_head(object); + assert(head->refcount > 0); + head->refcount--; +} + +void pn_object_free(void *object) +{ + pni_head_t *head = pni_head(object); + free(head); +} + +void *pn_incref(void *object) +{ + return pn_class_incref(PN_OBJECT, object); +} + +int pn_decref(void *object) +{ + return pn_class_decref(PN_OBJECT, object); +} + +int pn_refcount(void *object) +{ + return pn_class_refcount(PN_OBJECT, object); +} + +void pn_free(void *object) +{ + pn_class_free(PN_OBJECT, object); +} + +const pn_class_t *pn_class(void *object) +{ + return pn_class_reify(PN_OBJECT, object); +} + +uintptr_t pn_hashcode(void *object) +{ + return pn_class_hashcode(PN_OBJECT, object); +} + +intptr_t pn_compare(void *a, void *b) +{ + return pn_class_compare(PN_OBJECT, a, b); +} + +bool pn_equals(void *a, void *b) +{ + return !pn_compare(a, b); +} + +int pn_inspect(void *object, pn_string_t *dst) +{ + return pn_class_inspect(PN_OBJECT, object, dst); +} + +#define pn_weakref_new NULL +#define pn_weakref_initialize NULL +#define pn_weakref_finalize NULL +#define pn_weakref_free NULL + +static void pn_weakref_incref(void *object) {} +static void pn_weakref_decref(void *object) {} +static int pn_weakref_refcount(void *object) { return -1; } +static const pn_class_t *pn_weakref_reify(void *object) { + return PN_WEAKREF; +} +static uintptr_t pn_weakref_hashcode(void *object) { + return pn_hashcode(object); +} +static intptr_t pn_weakref_compare(void *a, void *b) { + return pn_compare(a, b); +} +static int pn_weakref_inspect(void *object, pn_string_t *dst) { + return pn_inspect(object, dst); +} + +const pn_class_t PN_WEAKREF[] = {PN_METACLASS(pn_weakref)}; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/record.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/object/record.c b/proton-c/src/core/object/record.c new file mode 100644 index 0000000..6f4fe0a --- /dev/null +++ b/proton-c/src/core/object/record.c @@ -0,0 +1,153 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <proton/object.h> +#include <stdlib.h> +#include <assert.h> + +typedef struct { + pn_handle_t key; + const pn_class_t *clazz; + void *value; +} pni_field_t; + +struct pn_record_t { + size_t size; + size_t capacity; + pni_field_t *fields; +}; + +static void pn_record_initialize(void *object) +{ + pn_record_t *record = (pn_record_t *) object; + record->size = 0; + record->capacity = 0; + record->fields = NULL; +} + +static void pn_record_finalize(void *object) +{ + pn_record_t *record = (pn_record_t *) object; + for (size_t i = 0; i < record->size; i++) { + pni_field_t *v = &record->fields[i]; + pn_class_decref(v->clazz, v->value); + } + free(record->fields); +} + +#define pn_record_hashcode NULL +#define pn_record_compare NULL +#define pn_record_inspect NULL + +pn_record_t *pn_record(void) +{ + static const pn_class_t clazz = PN_CLASS(pn_record); + pn_record_t *record = (pn_record_t *) pn_class_new(&clazz, sizeof(pn_record_t)); + pn_record_def(record, PN_LEGCTX, PN_VOID); + return record; +} + +static pni_field_t *pni_record_find(pn_record_t *record, pn_handle_t key) { + for (size_t i = 0; i < record->size; i++) { + pni_field_t *field = &record->fields[i]; + if (field->key == key) { + return field; + } + } + return NULL; +} + +static pni_field_t *pni_record_create(pn_record_t *record) { + record->size++; + if (record->size > record->capacity) { + record->fields = (pni_field_t *) realloc(record->fields, record->size * sizeof(pni_field_t)); + record->capacity = record->size; + } + pni_field_t *field = &record->fields[record->size - 1]; + field->key = 0; + field->clazz = NULL; + field->value = NULL; + return field; +} + +void pn_record_def(pn_record_t *record, pn_handle_t key, const pn_class_t *clazz) +{ + assert(record); + assert(clazz); + + pni_field_t *field = pni_record_find(record, key); + if (field) { + assert(field->clazz == clazz); + } else { + field = pni_record_create(record); + field->key = key; + field->clazz = clazz; + } +} + +bool pn_record_has(pn_record_t *record, pn_handle_t key) +{ + assert(record); + pni_field_t *field = pni_record_find(record, key); + if (field) { + return true; + } else { + return false; + } +} + +void *pn_record_get(pn_record_t *record, pn_handle_t key) +{ + assert(record); + pni_field_t *field = pni_record_find(record, key); + if (field) { + return field->value; + } else { + return NULL; + } +} + +void pn_record_set(pn_record_t *record, pn_handle_t key, void *value) +{ + assert(record); + + pni_field_t *field = pni_record_find(record, key); + if (field) { + void *old = field->value; + field->value = value; + pn_class_incref(field->clazz, value); + pn_class_decref(field->clazz, old); + } +} + +void pn_record_clear(pn_record_t *record) +{ + assert(record); + for (size_t i = 0; i < record->size; i++) { + pni_field_t *field = &record->fields[i]; + pn_class_decref(field->clazz, field->value); + field->key = 0; + field->clazz = NULL; + field->value = NULL; + } + record->size = 0; + pn_record_def(record, PN_LEGCTX, PN_VOID); +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/string.c ---------------------------------------------------------------------- diff --git a/proton-c/src/core/object/string.c b/proton-c/src/core/object/string.c new file mode 100644 index 0000000..13d0739 --- /dev/null +++ b/proton-c/src/core/object/string.c @@ -0,0 +1,269 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "platform/platform.h" + +#include <proton/error.h> +#include <proton/object.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> + +#define PNI_NULL_SIZE (-1) + +struct pn_string_t { + char *bytes; + ssize_t size; // PNI_NULL_SIZE (-1) means null + size_t capacity; +}; + +static void pn_string_finalize(void *object) +{ + pn_string_t *string = (pn_string_t *) object; + free(string->bytes); +} + +static uintptr_t pn_string_hashcode(void *object) +{ + pn_string_t *string = (pn_string_t *) object; + if (string->size == PNI_NULL_SIZE) { + return 0; + } + + uintptr_t hashcode = 1; + for (ssize_t i = 0; i < string->size; i++) { + hashcode = hashcode * 31 + string->bytes[i]; + } + return hashcode; +} + +static intptr_t pn_string_compare(void *oa, void *ob) +{ + pn_string_t *a = (pn_string_t *) oa; + pn_string_t *b = (pn_string_t *) ob; + if (a->size != b->size) { + return b->size - a->size; + } + + if (a->size == PNI_NULL_SIZE) { + return 0; + } else { + return memcmp(a->bytes, b->bytes, a->size); + } +} + +static int pn_string_inspect(void *obj, pn_string_t *dst) +{ + pn_string_t *str = (pn_string_t *) obj; + if (str->size == PNI_NULL_SIZE) { + return pn_string_addf(dst, "null"); + } + + int err = pn_string_addf(dst, "\""); + + for (int i = 0; i < str->size; i++) { + uint8_t c = str->bytes[i]; + if (isprint(c)) { + err = pn_string_addf(dst, "%c", c); + if (err) return err; + } else { + err = pn_string_addf(dst, "\\x%.2x", c); + if (err) return err; + } + } + + return pn_string_addf(dst, "\""); +} + +pn_string_t *pn_string(const char *bytes) +{ + return pn_stringn(bytes, bytes ? strlen(bytes) : 0); +} + +#define pn_string_initialize NULL + + +pn_string_t *pn_stringn(const char *bytes, size_t n) +{ + static const pn_class_t clazz = PN_CLASS(pn_string); + pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t)); + string->capacity = n ? n * sizeof(char) : 16; + string->bytes = (char *) malloc(string->capacity); + pn_string_setn(string, bytes, n); + return string; +} + +const char *pn_string_get(pn_string_t *string) +{ + assert(string); + if (string->size == PNI_NULL_SIZE) { + return NULL; + } else { + return string->bytes; + } +} + +size_t pn_string_size(pn_string_t *string) +{ + assert(string); + if (string->size == PNI_NULL_SIZE) { + return 0; + } else { + return string->size; + } +} + +int pn_string_set(pn_string_t *string, const char *bytes) +{ + return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0); +} + +int pn_string_grow(pn_string_t *string, size_t capacity) +{ + bool grow = false; + while (string->capacity < (capacity*sizeof(char) + 1)) { + string->capacity *= 2; + grow = true; + } + + if (grow) { + char *growed = (char *) realloc(string->bytes, string->capacity); + if (growed) { + string->bytes = growed; + } else { + return PN_ERR; + } + } + + return 0; +} + +int pn_string_setn(pn_string_t *string, const char *bytes, size_t n) +{ + int err = pn_string_grow(string, n); + if (err) return err; + + if (bytes) { + memcpy(string->bytes, bytes, n*sizeof(char)); + string->bytes[n] = '\0'; + string->size = n; + } else { + string->size = PNI_NULL_SIZE; + } + + return 0; +} + +ssize_t pn_string_put(pn_string_t *string, char *dst) +{ + assert(string); + assert(dst); + + if (string->size != PNI_NULL_SIZE) { + memcpy(dst, string->bytes, string->size + 1); + } + + return string->size; +} + +void pn_string_clear(pn_string_t *string) +{ + pn_string_set(string, NULL); +} + +int pn_string_format(pn_string_t *string, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + int err = pn_string_vformat(string, format, ap); + va_end(ap); + return err; +} + +int pn_string_vformat(pn_string_t *string, const char *format, va_list ap) +{ + pn_string_set(string, ""); + return pn_string_vaddf(string, format, ap); +} + +int pn_string_addf(pn_string_t *string, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + int err = pn_string_vaddf(string, format, ap); + va_end(ap); + return err; +} + +int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap) +{ + va_list copy; + + if (string->size == PNI_NULL_SIZE) { + return PN_ERR; + } + + while (true) { + va_copy(copy, ap); + int err = pni_vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy); + va_end(copy); + if (err < 0) { + return err; + } else if ((size_t) err >= string->capacity - string->size) { + pn_string_grow(string, string->size + err); + } else { + string->size += err; + return 0; + } + } +} + +char *pn_string_buffer(pn_string_t *string) +{ + assert(string); + return string->bytes; +} + +size_t pn_string_capacity(pn_string_t *string) +{ + assert(string); + return string->capacity - 1; +} + +int pn_string_resize(pn_string_t *string, size_t size) +{ + assert(string); + int err = pn_string_grow(string, size); + if (err) return err; + string->size = size; + string->bytes[size] = '\0'; + return 0; +} + +int pn_string_copy(pn_string_t *string, pn_string_t *src) +{ + assert(string); + return pn_string_setn(string, pn_string_get(src), pn_string_size(src)); +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
