// Copyright 2023 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/io/scope_map.h"

IREE_API_EXPORT void iree_io_scope_map_initialize(
    iree_allocator_t host_allocator, iree_io_scope_map_t* out_scope_map) {
  IREE_TRACE_ZONE_BEGIN(z0);
  out_scope_map->host_allocator = host_allocator;
  out_scope_map->count = 0;
  out_scope_map->capacity = 0;
  out_scope_map->entries = NULL;
  IREE_TRACE_ZONE_END(z0);
}

IREE_API_EXPORT void iree_io_scope_map_deinitialize(
    iree_io_scope_map_t* scope_map) {
  IREE_TRACE_ZONE_BEGIN(z0);
  iree_allocator_t host_allocator = scope_map->host_allocator;
  for (iree_host_size_t i = 0; i < scope_map->count; ++i) {
    iree_io_scope_map_entry_t* entry = scope_map->entries[i];
    iree_io_parameter_index_release(entry->index);
    iree_allocator_free(host_allocator, entry);
  }
  iree_allocator_free(host_allocator, scope_map->entries);
  IREE_TRACE_ZONE_END(z0);
}

IREE_API_EXPORT iree_status_t iree_io_scope_map_lookup(
    iree_io_scope_map_t* scope_map, iree_string_view_t scope,
    iree_io_parameter_index_t** out_index) {
  IREE_TRACE_ZONE_BEGIN(z0);
  IREE_TRACE_ZONE_APPEND_TEXT(z0, scope.data, scope.size);

  for (iree_host_size_t i = 0; i < scope_map->count; ++i) {
    iree_io_scope_map_entry_t* entry = scope_map->entries[i];
    if (iree_string_view_equal(scope, entry->scope)) {
      IREE_TRACE_ZONE_APPEND_TEXT(z0, "hit");
      *out_index = entry->index;
      IREE_TRACE_ZONE_END(z0);
      return iree_ok_status();
    }
  }
  IREE_TRACE_ZONE_APPEND_TEXT(z0, "miss");

  if (scope_map->count == scope_map->capacity) {
    IREE_RETURN_AND_END_ZONE_IF_ERROR(
        z0, iree_allocator_grow_array(
                scope_map->host_allocator,
                /*min_capacity=*/8, sizeof(scope_map->entries[0]),
                &scope_map->capacity, (void**)&scope_map->entries));
  }

  iree_io_scope_map_entry_t* entry = NULL;
  IREE_RETURN_AND_END_ZONE_IF_ERROR(
      z0, iree_allocator_malloc_with_trailing(scope_map->host_allocator,
                                              sizeof(*entry), scope.size,
                                              (void**)&entry));
  entry->scope =
      iree_make_string_view((const char*)entry + sizeof(*entry), scope.size);
  if (scope.size > 0) {
    memcpy((char*)entry->scope.data, scope.data, scope.size);
  }

  iree_status_t status =
      iree_io_parameter_index_create(scope_map->host_allocator, &entry->index);

  if (iree_status_is_ok(status)) {
    scope_map->entries[scope_map->count++] = entry;
    *out_index = entry->index;
  } else {
    iree_allocator_free(scope_map->host_allocator, entry);
  }
  IREE_TRACE_ZONE_END(z0);
  return status;
}

IREE_API_EXPORT iree_status_t iree_io_scope_map_dump(
    iree_io_scope_map_t* scope_map, iree_string_builder_t* builder) {
  for (iree_host_size_t i = 0; i < scope_map->count; ++i) {
    iree_string_view_t scope = scope_map->entries[i]->scope;
    iree_io_parameter_index_t* index = scope_map->entries[i]->index;
    IREE_RETURN_IF_ERROR(iree_io_parameter_index_dump(scope, index, builder));
  }
  return iree_ok_status();
}
