Program Listing for File t8_containers.cxx

Return to documentation for file (src/t8_data/t8_containers.cxx)

/*  This file is part of t8code.
  t8code is a C library to manage a collection (a forest) of multiple
  connected adaptive space-trees of general element classes in parallel.

  Copyright (C) 2015 the developers

  t8code is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  t8code is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with t8code; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <sc_containers.h>
#include <t8_data/t8_containers.h>
#include <t8_schemes/t8_scheme.hxx>

T8_EXTERN_C_BEGIN ();

#if T8_ENABLE_DEBUG
/* Query whether an element array is initialized properly. */
static int
t8_element_array_is_valid (const t8_element_array_t *element_array)
{
  int is_valid;

  /* Check that all pointers are not NULL */
  is_valid = element_array != NULL && element_array->scheme != NULL;

  if (!is_valid) {
    return 0;
  }

  /* Check that the element size of the scheme matches the size of data elements
   * stored in the array. */
  is_valid
    = is_valid && element_array->scheme->get_element_size (element_array->tree_class) == element_array->array.elem_size;

  return is_valid;
}
#endif

t8_element_array_t *
t8_element_array_new (const t8_scheme_c *scheme, const t8_eclass_t tree_class)
{
  t8_element_array_t *new_array;

  /* allocate memory */
  new_array = T8_ALLOC (t8_element_array_t, 1);
  /* initialize array */
  t8_element_array_init (new_array, scheme, tree_class);
  T8_ASSERT (t8_element_array_is_valid (new_array));

  return new_array;
}

t8_element_array_t *
t8_element_array_new_count (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const size_t num_elements)
{
  /* allocate memory */
  t8_element_array_t *new_array = T8_ALLOC (t8_element_array_t, 1);
  /* initialize array */
  t8_element_array_init_size (new_array, scheme, tree_class, num_elements);
  T8_ASSERT (t8_element_array_is_valid (new_array));

  return new_array;
}

void
t8_element_array_init (t8_element_array_t *element_array, const t8_scheme_c *scheme, const t8_eclass_t tree_class)
{
  T8_ASSERT (element_array != NULL);

  /* set the scheme and eclass */
  element_array->scheme = scheme;
  element_array->tree_class = tree_class;
  /* get the size of an element and initialize the array member */
  const size_t elem_size = scheme->get_element_size (tree_class);
  sc_array_init (&element_array->array, elem_size);
  T8_ASSERT (t8_element_array_is_valid (element_array));
}

void
t8_element_array_init_size (t8_element_array_t *element_array, const t8_scheme_c *scheme, const t8_eclass_t tree_class,
                            const size_t num_elements)
{
  t8_element_t *first_element;
  T8_ASSERT (element_array != NULL);

  element_array->scheme = scheme;
  element_array->tree_class = tree_class;
  /* allocate the elements */
  sc_array_init_size (&element_array->array, scheme->get_element_size (tree_class), num_elements);

  if (num_elements > 0) {
    /* Call t8_element_init for the elements */
    first_element = (t8_element_t *) sc_array_index (&element_array->array, 0);
    scheme->element_init (tree_class, num_elements, first_element);
  }
  T8_ASSERT (t8_element_array_is_valid (element_array));
}

void
t8_element_array_init_view (t8_element_array_t *view, const t8_element_array_t *array, const size_t offset,
                            const size_t length)
{
  T8_ASSERT (t8_element_array_is_valid (array));

  /* Initialize the element array.
   * Unfortunately, we have to cast away the constness to pass to sc_array_init_view.
   */
  sc_array_init_view (&view->array, &((t8_element_array_t *) array)->array, offset, length);
  /* Set the scheme */
  view->scheme = array->scheme;
  view->tree_class = array->tree_class;
  T8_ASSERT (t8_element_array_is_valid (view));
}

void
t8_element_array_init_data (t8_element_array_t *view, const t8_element_t *base, const t8_scheme_c *scheme,
                            const t8_eclass_t tree_class, const size_t elem_count)
{
  /* Initialize the element array */
  sc_array_init_data (&view->array, (void *) base, scheme->get_element_size (tree_class), elem_count);
  /* set the scheme */
  view->scheme = scheme;
  view->tree_class = tree_class;
  T8_ASSERT (t8_element_array_is_valid (view));
}

void
t8_element_array_init_copy (t8_element_array_t *element_array, const t8_scheme_c *scheme, const t8_eclass_t tree_class,
                            const t8_element_t *data, const size_t num_elements)
{
  sc_array_t *array;
  T8_ASSERT (element_array != NULL);

  t8_element_array_init (element_array, scheme, tree_class);

  array = &element_array->array;
#if T8_ENABLE_DEBUG
  /* Check if the elements in data are valid for scheme */
  {
    size_t ielem;
    const t8_element_t *element;
    const size_t size = scheme->get_element_size (tree_class);
    for (ielem = 0; ielem < num_elements; ielem++) {
      /* data is of incomplete type, we thus have to manually set the address
       * of the ielem-th t8_element */
      element = (const t8_element_t *) (((char *) data) + ielem * size);
      T8_ASSERT (scheme->element_is_valid (tree_class, element));
    }
  }
#endif
  /* Allocate enough memory for the new elements */
  sc_array_init_size (array, scheme->get_element_size (tree_class), num_elements);
  /* Copy the elements in data */
  memcpy (array->array, data, num_elements * array->elem_size);
}

void
t8_element_array_resize (t8_element_array_t *element_array, const size_t new_count)
{
  size_t old_count;
  const t8_eclass_t tree_class = element_array->tree_class;
  T8_ASSERT (t8_element_array_is_valid (element_array));
  /* Store the old number of elements */
  old_count = t8_element_array_get_count (element_array);
  if (old_count < new_count) {
    /* if the new_count is larger than the previous count, we need to
    * call t8_element_init on the newly allocated elements. */
    sc_array_resize (&element_array->array, new_count);
    t8_element_t *first_new_elem;
    /* Get the first newly allocated element */
    first_new_elem = t8_element_array_index_locidx_mutable (element_array, old_count);
    /* Call t8_element_init on all new elements */
    element_array->scheme->element_init (tree_class, new_count - old_count, first_new_elem);
  }
  else if (old_count > new_count) {
    t8_element_t *first_old_elem;
    /* Get the first element to deinit */
    first_old_elem = t8_element_array_index_locidx_mutable (element_array, new_count);
    element_array->scheme->element_deinit (tree_class, old_count - new_count, first_old_elem);
    sc_array_resize (&element_array->array, new_count);
  }
  else {
    T8_ASSERT (new_count == element_array->array.elem_count);
    /* Free the allocated, but unused memory. */
    sc_array_resize (&element_array->array, new_count);
  }
}

void
t8_element_array_copy (t8_element_array_t *dest, const t8_element_array_t *src)
{
  T8_ASSERT (t8_element_array_is_valid (dest));
  T8_ASSERT (t8_element_array_is_valid (src));
  T8_ASSERT (dest->scheme == src->scheme);
  sc_array_copy (&dest->array, (sc_array_t *) &src->array); /* need to convert src->array to non-const */
}

t8_element_t *
t8_element_array_push (t8_element_array_t *element_array)
{
  t8_element_t *new_element;
  T8_ASSERT (t8_element_array_is_valid (element_array));
  new_element = (t8_element_t *) sc_array_push (&element_array->array);
  element_array->scheme->element_init (element_array->tree_class, 1, new_element);
  return new_element;
}

t8_element_t *
t8_element_array_push_count (t8_element_array_t *element_array, const size_t count)
{
  t8_element_t *new_elements;
  T8_ASSERT (t8_element_array_is_valid (element_array));
  /* grow the array */
  new_elements = (t8_element_t *) sc_array_push_count (&element_array->array, count);
  /* initialize the elements */
  element_array->scheme->element_init (element_array->tree_class, count, new_elements);
  return new_elements;
}

const t8_element_t *
t8_element_array_index_locidx (const t8_element_array_t *element_array, const t8_locidx_t index)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  return (const t8_element_t *) t8_sc_array_index_locidx (&element_array->array, index);
}

const t8_element_t *
t8_element_array_index_int (const t8_element_array_t *element_array, const int index)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  return (const t8_element_t *) sc_array_index_int ((sc_array_t *) &element_array->array,
                                                    index); /* Need to convert element_array->array to non-const */
}

t8_element_t *
t8_element_array_index_locidx_mutable (t8_element_array_t *element_array, const t8_locidx_t index)
{
  return (t8_element_t *) t8_element_array_index_locidx (element_array, index);
}

t8_element_t *
t8_element_array_index_int_mutable (t8_element_array_t *element_array, const int index)
{
  return (t8_element_t *) t8_element_array_index_int (element_array, index);
}

const t8_scheme_c *
t8_element_array_get_scheme (const t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  return element_array->scheme;
}

t8_eclass_t
t8_element_array_get_tree_class (const t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  return element_array->tree_class;
}

size_t
t8_element_array_get_count (const t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  return element_array->array.elem_count;
}

size_t
t8_element_array_get_size (const t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  return element_array->scheme->get_element_size (element_array->tree_class);
}

const t8_element_t *
t8_element_array_get_data (const t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));

  if (element_array->array.elem_count > 0) {
    return (t8_element_t *) t8_element_array_index_locidx (element_array, 0);
  }
  else {
    return NULL;
  }
}

t8_element_t *
t8_element_array_get_data_mutable (t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));

  return (t8_element_t *) t8_element_array_get_data (element_array);
}

const sc_array_t *
t8_element_array_get_array (const t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));

  return &element_array->array;
}

sc_array_t *
t8_element_array_get_array_mutable (t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));

  return &element_array->array;
}

void
t8_element_array_reset (t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  const size_t count = t8_element_array_get_count (element_array);
  if (count > 0) {
    t8_element_t *first_elem = t8_element_array_index_locidx_mutable (element_array, 0);
    element_array->scheme->element_deinit (element_array->tree_class, count, first_elem);
  }
  sc_array_reset (&element_array->array);
}

void
t8_element_array_truncate (t8_element_array_t *element_array)
{
  T8_ASSERT (t8_element_array_is_valid (element_array));
  const size_t count = t8_element_array_get_count (element_array);
  if (count > 0) {
    t8_element_t *first_elem = t8_element_array_index_locidx_mutable (element_array, 0);
    element_array->scheme->element_deinit (element_array->tree_class, count, first_elem);
  }
  sc_array_truncate (&element_array->array);
}

T8_EXTERN_C_END ();