| /* |
| * 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. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include <arrow-glib/buffer.hpp> |
| #include <arrow-glib/error.hpp> |
| |
| G_BEGIN_DECLS |
| |
| /** |
| * SECTION: buffer |
| * @section_id: buffer-classes |
| * @title: Buffer classes |
| * @include: arrow-glib/arrow-glib.h |
| * |
| * #GArrowBuffer is a class for keeping data. Other classes such as |
| * #GArrowArray and #GArrowTensor can use data in buffer. |
| * |
| * #GArrowBuffer is immutable. |
| * |
| * #GArrowMutableBuffer is mutable. |
| * |
| * #GArrowResizableBuffer is mutable and resizable. |
| */ |
| |
| typedef struct GArrowBufferPrivate_ { |
| std::shared_ptr<arrow::Buffer> buffer; |
| GBytes *data; |
| } GArrowBufferPrivate; |
| |
| enum { |
| PROP_0, |
| PROP_BUFFER, |
| PROP_DATA |
| }; |
| |
| G_DEFINE_TYPE_WITH_PRIVATE(GArrowBuffer, garrow_buffer, G_TYPE_OBJECT) |
| |
| #define GARROW_BUFFER_GET_PRIVATE(obj) \ |
| static_cast<GArrowBufferPrivate *>( \ |
| garrow_buffer_get_instance_private( \ |
| GARROW_BUFFER(obj))) |
| |
| static void |
| garrow_buffer_dispose(GObject *object) |
| { |
| auto priv = GARROW_BUFFER_GET_PRIVATE(object); |
| |
| if (priv->data) { |
| g_bytes_unref(priv->data); |
| priv->data = nullptr; |
| } |
| |
| G_OBJECT_CLASS(garrow_buffer_parent_class)->dispose(object); |
| } |
| |
| static void |
| garrow_buffer_finalize(GObject *object) |
| { |
| auto priv = GARROW_BUFFER_GET_PRIVATE(object); |
| |
| priv->buffer = nullptr; |
| |
| G_OBJECT_CLASS(garrow_buffer_parent_class)->finalize(object); |
| } |
| |
| static void |
| garrow_buffer_set_property(GObject *object, |
| guint prop_id, |
| const GValue *value, |
| GParamSpec *pspec) |
| { |
| auto priv = GARROW_BUFFER_GET_PRIVATE(object); |
| |
| switch (prop_id) { |
| case PROP_BUFFER: |
| priv->buffer = |
| *static_cast<std::shared_ptr<arrow::Buffer> *>(g_value_get_pointer(value)); |
| break; |
| case PROP_DATA: |
| priv->data = static_cast<GBytes *>(g_value_dup_boxed(value)); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| garrow_buffer_get_property(GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec) |
| { |
| auto priv = GARROW_BUFFER_GET_PRIVATE(object); |
| |
| switch (prop_id) { |
| case PROP_DATA: |
| g_value_set_boxed(value, priv->data); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| garrow_buffer_init(GArrowBuffer *object) |
| { |
| } |
| |
| static void |
| garrow_buffer_class_init(GArrowBufferClass *klass) |
| { |
| GParamSpec *spec; |
| |
| auto gobject_class = G_OBJECT_CLASS(klass); |
| |
| gobject_class->dispose = garrow_buffer_dispose; |
| gobject_class->finalize = garrow_buffer_finalize; |
| gobject_class->set_property = garrow_buffer_set_property; |
| gobject_class->get_property = garrow_buffer_get_property; |
| |
| spec = g_param_spec_pointer("buffer", |
| "Buffer", |
| "The raw std::shared<arrow::Buffer> *", |
| static_cast<GParamFlags>(G_PARAM_WRITABLE | |
| G_PARAM_CONSTRUCT_ONLY)); |
| g_object_class_install_property(gobject_class, PROP_BUFFER, spec); |
| |
| spec = g_param_spec_boxed("data", |
| "Data", |
| "The raw data passed as GBytes *", |
| G_TYPE_BYTES, |
| static_cast<GParamFlags>(G_PARAM_READWRITE | |
| G_PARAM_CONSTRUCT_ONLY)); |
| g_object_class_install_property(gobject_class, PROP_DATA, spec); |
| } |
| |
| /** |
| * garrow_buffer_new: |
| * @data: (array length=size): Data for the buffer. |
| * They aren't owned by the new buffer. |
| * You must not free the data while the new buffer is alive. |
| * @size: The number of bytes of the data. |
| * |
| * Returns: A newly created #GArrowBuffer. |
| * |
| * Since: 0.3.0 |
| */ |
| GArrowBuffer * |
| garrow_buffer_new(const guint8 *data, gint64 size) |
| { |
| auto arrow_buffer = std::make_shared<arrow::Buffer>(data, size); |
| return garrow_buffer_new_raw(&arrow_buffer); |
| } |
| |
| /** |
| * garrow_buffer_new_bytes: |
| * @data: Data for the buffer. |
| * |
| * Returns: A newly created #GArrowBuffer. |
| * |
| * Since: 0.9.0 |
| */ |
| GArrowBuffer * |
| garrow_buffer_new_bytes(GBytes *data) |
| { |
| size_t data_size; |
| auto raw_data = g_bytes_get_data(data, &data_size); |
| auto arrow_buffer = |
| std::make_shared<arrow::Buffer>(static_cast<const uint8_t *>(raw_data), |
| data_size); |
| return garrow_buffer_new_raw_bytes(&arrow_buffer, data); |
| } |
| |
| /** |
| * garrow_buffer_equal: |
| * @buffer: A #GArrowBuffer. |
| * @other_buffer: A #GArrowBuffer to be compared. |
| * |
| * Returns: %TRUE if both of them have the same data, %FALSE |
| * otherwise. |
| * |
| * Since: 0.4.0 |
| */ |
| gboolean |
| garrow_buffer_equal(GArrowBuffer *buffer, GArrowBuffer *other_buffer) |
| { |
| const auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| const auto arrow_other_buffer = garrow_buffer_get_raw(other_buffer); |
| return arrow_buffer->Equals(*arrow_other_buffer); |
| } |
| |
| /** |
| * garrow_buffer_equal_n_bytes: |
| * @buffer: A #GArrowBuffer. |
| * @other_buffer: A #GArrowBuffer to be compared. |
| * @n_bytes: The number of first bytes to be compared. |
| * |
| * Returns: %TRUE if both of them have the same data in the first |
| * `n_bytes`, %FALSE otherwise. |
| * |
| * Since: 0.4.0 |
| */ |
| gboolean |
| garrow_buffer_equal_n_bytes(GArrowBuffer *buffer, |
| GArrowBuffer *other_buffer, |
| gint64 n_bytes) |
| { |
| const auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| const auto arrow_other_buffer = garrow_buffer_get_raw(other_buffer); |
| return arrow_buffer->Equals(*arrow_other_buffer, n_bytes); |
| } |
| |
| /** |
| * garrow_buffer_is_mutable: |
| * @buffer: A #GArrowBuffer. |
| * |
| * Returns: %TRUE if the buffer is mutable, %FALSE otherwise. |
| * |
| * Since: 0.3.0 |
| */ |
| gboolean |
| garrow_buffer_is_mutable(GArrowBuffer *buffer) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| return arrow_buffer->is_mutable(); |
| } |
| |
| /** |
| * garrow_buffer_get_capacity: |
| * @buffer: A #GArrowBuffer. |
| * |
| * Returns: The number of bytes that where allocated for the buffer in |
| * total. |
| * |
| * Since: 0.3.0 |
| */ |
| gint64 |
| garrow_buffer_get_capacity(GArrowBuffer *buffer) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| return arrow_buffer->capacity(); |
| } |
| |
| /** |
| * garrow_buffer_get_data: |
| * @buffer: A #GArrowBuffer. |
| * |
| * Returns: (transfer full): The data of the buffer. The data is owned by |
| * the buffer. You should not free or modify the data. |
| * |
| * Since: 0.3.0 |
| */ |
| GBytes * |
| garrow_buffer_get_data(GArrowBuffer *buffer) |
| { |
| auto priv = GARROW_BUFFER_GET_PRIVATE(buffer); |
| if (priv->data) { |
| g_bytes_ref(priv->data); |
| return priv->data; |
| } |
| |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| auto data = g_bytes_new_static(arrow_buffer->data(), |
| arrow_buffer->size()); |
| return data; |
| } |
| |
| /** |
| * garrow_buffer_get_mutable_data: |
| * @buffer: A #GArrowBuffer. |
| * |
| * Returns: (transfer full) (nullable): The data of the buffer. If the |
| * buffer is imutable, it returns %NULL. The data is owned by the |
| * buffer. You should not free the data. |
| * |
| * Since: 0.3.0 |
| */ |
| GBytes * |
| garrow_buffer_get_mutable_data(GArrowBuffer *buffer) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| if (!arrow_buffer->is_mutable()) { |
| return NULL; |
| } |
| |
| auto priv = GARROW_BUFFER_GET_PRIVATE(buffer); |
| if (priv->data) { |
| g_bytes_ref(priv->data); |
| return priv->data; |
| } |
| |
| return g_bytes_new_static(arrow_buffer->mutable_data(), |
| arrow_buffer->size()); |
| } |
| |
| /** |
| * garrow_buffer_get_size: |
| * @buffer: A #GArrowBuffer. |
| * |
| * Returns: The number of bytes that might have valid data. |
| * |
| * Since: 0.3.0 |
| */ |
| gint64 |
| garrow_buffer_get_size(GArrowBuffer *buffer) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| return arrow_buffer->size(); |
| } |
| |
| /** |
| * garrow_buffer_get_parent: |
| * @buffer: A #GArrowBuffer. |
| * |
| * Returns: (nullable) (transfer full): |
| * The parent #GArrowBuffer or %NULL. |
| * |
| * Since: 0.3.0 |
| */ |
| GArrowBuffer * |
| garrow_buffer_get_parent(GArrowBuffer *buffer) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| auto arrow_parent_buffer = arrow_buffer->parent(); |
| |
| if (arrow_parent_buffer) { |
| auto priv = GARROW_BUFFER_GET_PRIVATE(buffer); |
| return garrow_buffer_new_raw_bytes(&arrow_parent_buffer, priv->data); |
| } else { |
| return NULL; |
| } |
| } |
| |
| /** |
| * garrow_buffer_copy: |
| * @buffer: A #GArrowBuffer. |
| * @start: An offset of data to be copied in byte. |
| * @size: The number of bytes to be copied from the start. |
| * @error: (nullable): Return location for a #GError or %NULL. |
| * |
| * Returns: (nullable) (transfer full): |
| * A newly copied #GArrowBuffer on success, %NULL on error. |
| * |
| * Since: 0.3.0 |
| */ |
| GArrowBuffer * |
| garrow_buffer_copy(GArrowBuffer *buffer, |
| gint64 start, |
| gint64 size, |
| GError **error) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(buffer); |
| std::shared_ptr<arrow::Buffer> arrow_copied_buffer; |
| auto status = arrow_buffer->Copy(start, size, &arrow_copied_buffer); |
| if (garrow_error_check(error, status, "[buffer][copy]")) { |
| return garrow_buffer_new_raw(&arrow_copied_buffer); |
| } else { |
| return NULL; |
| } |
| } |
| |
| /** |
| * garrow_buffer_slice: |
| * @buffer: A #GArrowBuffer. |
| * @offset: An offset in the buffer data in byte. |
| * @size: The number of bytes of the sliced data. |
| * |
| * Returns: (transfer full): A newly created #GArrowBuffer that shares |
| * data of the base #GArrowBuffer. The created #GArrowBuffer has data |
| * start with offset from the base buffer data and are the specified |
| * bytes size. |
| * |
| * Since: 0.3.0 |
| */ |
| GArrowBuffer * |
| garrow_buffer_slice(GArrowBuffer *buffer, gint64 offset, gint64 size) |
| { |
| auto arrow_parent_buffer = garrow_buffer_get_raw(buffer); |
| auto arrow_buffer = std::make_shared<arrow::Buffer>(arrow_parent_buffer, |
| offset, |
| size); |
| auto priv = GARROW_BUFFER_GET_PRIVATE(buffer); |
| return garrow_buffer_new_raw_bytes(&arrow_buffer, priv->data); |
| } |
| |
| |
| G_DEFINE_TYPE(GArrowMutableBuffer, |
| garrow_mutable_buffer, |
| GARROW_TYPE_BUFFER) |
| |
| static void |
| garrow_mutable_buffer_init(GArrowMutableBuffer *object) |
| { |
| } |
| |
| static void |
| garrow_mutable_buffer_class_init(GArrowMutableBufferClass *klass) |
| { |
| } |
| |
| /** |
| * garrow_mutable_buffer_new: |
| * @data: (array length=size): Data for the buffer. |
| * They aren't owned by the new buffer. |
| * You must not free the data while the new buffer is alive. |
| * @size: The number of bytes of the data. |
| * |
| * Returns: A newly created #GArrowMutableBuffer. |
| * |
| * Since: 0.3.0 |
| */ |
| GArrowMutableBuffer * |
| garrow_mutable_buffer_new(guint8 *data, gint64 size) |
| { |
| auto arrow_buffer = std::make_shared<arrow::MutableBuffer>(data, size); |
| return garrow_mutable_buffer_new_raw(&arrow_buffer); |
| } |
| |
| /** |
| * garrow_mutable_buffer_new_bytes: |
| * @data: Data for the buffer. |
| * |
| * Returns: A newly created #GArrowMutableBuffer. |
| * |
| * Since: 0.9.0 |
| */ |
| GArrowMutableBuffer * |
| garrow_mutable_buffer_new_bytes(GBytes *data) |
| { |
| size_t data_size; |
| auto raw_data = g_bytes_get_data(data, &data_size); |
| auto mutable_raw_data = const_cast<gpointer>(raw_data); |
| auto arrow_buffer = |
| std::make_shared<arrow::MutableBuffer>(static_cast<uint8_t *>(mutable_raw_data), |
| data_size); |
| return garrow_mutable_buffer_new_raw_bytes(&arrow_buffer, data); |
| } |
| |
| /** |
| * garrow_mutable_buffer_slice: |
| * @buffer: A #GArrowMutableBuffer. |
| * @offset: An offset in the buffer data in byte. |
| * @size: The number of bytes of the sliced data. |
| * |
| * Returns: (transfer full): A newly created #GArrowMutableBuffer that |
| * shares data of the base #GArrowMutableBuffer. The created |
| * #GArrowMutableBuffer has data start with offset from the base |
| * buffer data and are the specified bytes size. |
| * |
| * Since: 0.3.0 |
| */ |
| GArrowMutableBuffer * |
| garrow_mutable_buffer_slice(GArrowMutableBuffer *buffer, |
| gint64 offset, |
| gint64 size) |
| { |
| auto arrow_parent_buffer = garrow_buffer_get_raw(GARROW_BUFFER(buffer)); |
| auto arrow_buffer = |
| std::make_shared<arrow::MutableBuffer>(arrow_parent_buffer, |
| offset, |
| size); |
| auto priv = GARROW_BUFFER_GET_PRIVATE(buffer); |
| return garrow_mutable_buffer_new_raw_bytes(&arrow_buffer, priv->data); |
| } |
| |
| /** |
| * garrow_mutable_buffer_set_data: |
| * @buffer: A #GArrowMutableBuffer. |
| * @offset: A write offset in the buffer data in byte. |
| * @data: (array length=size): The data to be written. |
| * @size: The number of bytes of the data to be written. |
| * @error: (nullable): Return location for a #GError or %NULL. |
| * |
| * Returns: %TRUE on success, %FALSE otherwise. |
| * |
| * Since: 0.12.0 |
| */ |
| gboolean |
| garrow_mutable_buffer_set_data(GArrowMutableBuffer *buffer, |
| gint64 offset, |
| const guint8 *data, |
| gint64 size, |
| GError **error) |
| { |
| const gchar *context = "[mutable-buffer][set-data]"; |
| auto arrow_buffer = garrow_buffer_get_raw(GARROW_BUFFER(buffer)); |
| if (offset + size > arrow_buffer->size()) { |
| g_set_error(error, |
| GARROW_ERROR, |
| GARROW_ERROR_INVALID, |
| "%s: Data is too large: " |
| "<(%" G_GINT64_FORMAT " + %" G_GINT64_FORMAT ") > " |
| "(%" G_GINT64_FORMAT ")>", |
| context, |
| offset, |
| size, |
| arrow_buffer->size()); |
| return FALSE; |
| } |
| memcpy(arrow_buffer->mutable_data() + offset, data, size); |
| return TRUE; |
| } |
| |
| |
| G_DEFINE_TYPE(GArrowResizableBuffer, |
| garrow_resizable_buffer, |
| GARROW_TYPE_MUTABLE_BUFFER) |
| |
| static void |
| garrow_resizable_buffer_init(GArrowResizableBuffer *object) |
| { |
| } |
| |
| static void |
| garrow_resizable_buffer_class_init(GArrowResizableBufferClass *klass) |
| { |
| } |
| |
| /** |
| * garrow_resizable_buffer_new: |
| * @initial_size: The initial buffer size in bytes. |
| * @error: (nullable): Return location for a #GError or %NULL. |
| * |
| * Returns: (nullable): A newly created #GArrowResizableBuffer. |
| * |
| * Since: 0.10.0 |
| */ |
| GArrowResizableBuffer * |
| garrow_resizable_buffer_new(gint64 initial_size, |
| GError **error) |
| { |
| std::shared_ptr<arrow::ResizableBuffer> arrow_buffer; |
| auto status = arrow::AllocateResizableBuffer(initial_size, &arrow_buffer); |
| if (garrow_error_check(error, status, "[resizable-buffer][new]")) { |
| return garrow_resizable_buffer_new_raw(&arrow_buffer); |
| } else { |
| return NULL; |
| } |
| } |
| |
| |
| /** |
| * garrow_resizable_buffer_resize: |
| * @buffer: A #GArrowResizableBuffer. |
| * @new_size: The new buffer size in bytes. |
| * @error: (nullable): Return location for a #GError or %NULL. |
| * |
| * Returns: %TRUE on success, %FALSE if there was an error. |
| * |
| * Since: 0.3.0 |
| */ |
| gboolean |
| garrow_resizable_buffer_resize(GArrowResizableBuffer *buffer, |
| gint64 new_size, |
| GError **error) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(GARROW_BUFFER(buffer)); |
| auto arrow_resizable_buffer = |
| std::static_pointer_cast<arrow::ResizableBuffer>(arrow_buffer); |
| auto status = arrow_resizable_buffer->Resize(new_size); |
| return garrow_error_check(error, status, "[resizable-buffer][resize]"); |
| } |
| |
| /** |
| * garrow_resizable_buffer_reserve: |
| * @buffer: A #GArrowResizableBuffer. |
| * @new_capacity: The new buffer capacity in bytes. |
| * @error: (nullable): Return location for a #GError or %NULL. |
| * |
| * Returns: %TRUE on success, %FALSE if there was an error. |
| * |
| * Since: 0.3.0 |
| */ |
| gboolean |
| garrow_resizable_buffer_reserve(GArrowResizableBuffer *buffer, |
| gint64 new_capacity, |
| GError **error) |
| { |
| auto arrow_buffer = garrow_buffer_get_raw(GARROW_BUFFER(buffer)); |
| auto arrow_resizable_buffer = |
| std::static_pointer_cast<arrow::ResizableBuffer>(arrow_buffer); |
| auto status = arrow_resizable_buffer->Reserve(new_capacity); |
| return garrow_error_check(error, status, "[resizable-buffer][capacity]"); |
| } |
| |
| |
| G_END_DECLS |
| |
| GArrowBuffer * |
| garrow_buffer_new_raw(std::shared_ptr<arrow::Buffer> *arrow_buffer) |
| { |
| return garrow_buffer_new_raw_bytes(arrow_buffer, nullptr); |
| } |
| |
| GArrowBuffer * |
| garrow_buffer_new_raw_bytes(std::shared_ptr<arrow::Buffer> *arrow_buffer, |
| GBytes *data) |
| { |
| auto buffer = GARROW_BUFFER(g_object_new(GARROW_TYPE_BUFFER, |
| "buffer", arrow_buffer, |
| "data", data, |
| NULL)); |
| return buffer; |
| } |
| |
| std::shared_ptr<arrow::Buffer> |
| garrow_buffer_get_raw(GArrowBuffer *buffer) |
| { |
| if (!buffer) |
| return nullptr; |
| |
| auto priv = GARROW_BUFFER_GET_PRIVATE(buffer); |
| return priv->buffer; |
| } |
| |
| GArrowMutableBuffer * |
| garrow_mutable_buffer_new_raw(std::shared_ptr<arrow::MutableBuffer> *arrow_buffer) |
| { |
| return garrow_mutable_buffer_new_raw_bytes(arrow_buffer, nullptr); |
| } |
| |
| GArrowMutableBuffer * |
| garrow_mutable_buffer_new_raw_bytes(std::shared_ptr<arrow::MutableBuffer> *arrow_buffer, |
| GBytes *data) |
| { |
| auto buffer = GARROW_MUTABLE_BUFFER(g_object_new(GARROW_TYPE_MUTABLE_BUFFER, |
| "buffer", arrow_buffer, |
| "data", data, |
| NULL)); |
| return buffer; |
| } |
| |
| GArrowResizableBuffer * |
| garrow_resizable_buffer_new_raw(std::shared_ptr<arrow::ResizableBuffer> *arrow_buffer) |
| { |
| auto buffer = |
| GARROW_RESIZABLE_BUFFER(g_object_new(GARROW_TYPE_RESIZABLE_BUFFER, |
| "buffer", arrow_buffer, |
| NULL)); |
| return buffer; |
| } |