/* Objective Modula-2 Compiler (objm2c)
 *
 *  @file objm2_key_value_storage.h
 *
 *  Low level key/value table storage interface
 *
 *  Author: Benjamin Kowarsch
 *
 *  Copyright (C) 2009 The Objective Modula-2 Project. All rights reserved.
 *
 *  License:
 *
 *  Redistribution  and  use  in source  and  binary forms,  with  or  without
 *  modification, are permitted provided that the following conditions are met
 *
 *  1) This file,  or any part thereof,  may  NOT  be hosted on websites which
 *     contain advertising,  unless specific prior written permission has been
 *     obtained.  The licensor will grant such permission  upon request at its
 *     sole discretion to websites the licensor does  NOT  consider abusive in
 *     their  use  of advertising.  Small notices  in the footer  of a website
 *     naming corporate rights holders,  infrastructure providers  or sponsors
 *     are not considered advertising in the context of this license.
 *
 *  2) Redistributions  of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *  3) Redistributions  in binary form  must  reproduce  the  above  copyright
 *     notice,  this list of conditions  and  the following disclaimer  in the
 *     documentation and other materials provided with the distribution.
 *
 *  4) Neither the author's name nor the names of any contributors may be used
 *     to endorse  or  promote  products  derived  from this software  without
 *     specific prior written permission.
 *
 *  5) Where this list of conditions  or  the following disclaimer, in part or
 *     as a whole is overruled  or  nullified by applicable law, no permission
 *     is granted to use the software.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY  AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
 * CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS; OR BUSINESS
 * INTERRUPTION)  HOWEVER  CAUSED  AND ON ANY THEORY OF LIABILITY,  WHETHER IN
 * CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *  
 *  Version history:
 *
 *   2.00   2009-01-31   BK   new file from various spin-offs of v.1.x
 *          2009-01-22   BK   added status parameter to all functions
 *          2009-04-23   BK   retrieval both by copy and by reference
 */

#ifndef OBJM2_KVS_H
#define OBJM2_KVS_H


#include "common_types.h"


// ---------------------------------------------------------------------------
// Default KVS table size
// ---------------------------------------------------------------------------

#define OBJM2_KVS_DEFAULT_TABLE_SIZE 20011


// ---------------------------------------------------------------------------
// Opaque key-value table handle type
// ---------------------------------------------------------------------------
//
// WARNING:  Objects of this opaque type should  only be accessed through this
// public interface.  DO NOT EVER attempt to bypass the public interface.
//
// The internal data structure of this opaque type is  HIDDEN  and  MAY CHANGE
// at any time WITHOUT NOTICE.  Accessing the internal data structure directly
// other than  through the  functions  in this public interface is  UNSAFE and
// may result in an inconsistent program state or a crash.

typedef opaque_t objm2_kvs_table_t;


// ---------------------------------------------------------------------------
// Value data pointer type
// ---------------------------------------------------------------------------

typedef void *objm2_kvs_data_t;


// ---------------------------------------------------------------------------
// Status codes
// ---------------------------------------------------------------------------

typedef /* objm2_kvs_status_t */ enum {
    OBJM2_KVS_STATUS_UNDEFINED = -1,
    OBJM2_KVS_STATUS_SUCCESS = 1,
    OBJM2_KVS_STATUS_INVALID_KEY,
    OBJM2_KVS_STATUS_INVALID_DATA,
    OBJM2_KVS_STATUS_KEY_NOT_UNIQUE,
    OBJM2_KVS_STATUS_UNABLE_TO_ALLOCATE,
    OBJM2_KVS_STATUS_ENTRY_NOT_FOUND,
    OBJM2_KVS_STATUS_ENTRY_PENDING_REMOVAL,
    OBJM2_KVS_STATUS_INVALID_ENTRY
} objm2_kvs_status_t;


// ---------------------------------------------------------------------------
// function:  objm2_kvs_new_table(size, status)
// ---------------------------------------------------------------------------
//
// Creates  and returns  a new KVS table object with <size> number of buckets.
// If  zero is passed in <size>,  then  the new table will be created with the
// default table size  as  defined  by  OBJM2_KVS_DEFAULT_TABLE_SIZE.  Returns
// NULL if the KVS table object could not be created.

// The status of the operation  is passed back in <status>,  unless  NULL  was
// passed in for <status>.

objm2_kvs_table_t objm2_kvs_new_table(cardinal size,
                            objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_add_entry(table, key, value, len, status)
// ---------------------------------------------------------------------------
//
// Adds a value for key <key> to KVS table <table>.  The value to be stored is
// passed as a pointer in <value>.  Values are copied  into a  newly allocated
// container  within the KVS table.  The number of bytes to copy is passed  in
// <len>.  If a  zero-value  is passed  in <len>,  then  the pointer passed in
// <value> is treated as a pointer to a C string and data will be copied up to
// and including the first zero-value byte encountered.  The initial reference
// count of the new entry is set to one.
//
// Keys must be unique.  Existing entries are not replaced.  Duplicate entries
// are not added.  The  status  of  the operation  is passed back in <status>,
// unless NULL was passed in for <status>.

void objm2_kvs_add_entry(objm2_kvs_table_t table,
                                  uint32_t key,
                          objm2_kvs_data_t value,
                                  cardinal len,
                        objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_entry_exists(table, key, status)
// ---------------------------------------------------------------------------
//
// Returns  true  if a  valid entry  for <key> exists  in  KVS  table <table>,
// returns false otherwise.  If an entry is found,  valid or invalid,  then it
// will be cached internally  and a subsequent search request for the same key
// will check the cached entry first, which is slighly faster than a lookup of
// a  non-cached entry.  The  reference count  of the entry is  not  modified.
// The  status  of the operation  is passed back in <status>,  unless NULL was
// passed in for <status>.

bool objm2_kvs_entry_exists(objm2_kvs_table_t table,
                                     uint32_t key,
                           objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_value_for_key(table, key, copy, len, status)
// ---------------------------------------------------------------------------
//
// Retrieves the table entry stored in <table> for <key>  either by copy or by
// reference.  If  true  is passed in for <copy>,  then  the function operates
// in by-copy mode,  otherwise it operates in by-reference mode.
//
// In by-copy mode,  if the entry exists,  a newly allocated copy of its value
// is created,  and  a pointer to it is returned as function result.  The size
// of the entry's value (in bytes)  is passed back in <len>,  unless the entry
// was stored as a  C string,  in which case zero is passed back in <len>.  In
// by-copy mode,  the reference count for the entry is  not  incremented.
//
// In by-reference mode,  if the entry exists,  a pointer to the entry's value
// is returned as function result.  The size of the  entry's value  (in bytes)
// is passed back in <len>,  unless  the entry  was stored as a  C string,  in
// which case zero is passed back in <len>. In by-reference mode the reference
// count of the entry  is  incremented.
//
// If the entry has been successfully retrieved,  then it is cached within the
// table,  regardless of whether it was returned by copy or by reference.
//
// If the entry does not exist,  or,  if it has been marked for removal,  then
// NULL  is  returned,  no  data  is copied,  no table meta data  is modified,
// no entry meta data is modified,  and <len> remains unchanged.
//
// The  status  of the operation  is passed back in <status>,  unless NULL was
// passed in for <status>.

/*const*/ objm2_kvs_data_t objm2_kvs_value_for_key(objm2_kvs_table_t table,
                                                        uint32_t key,
                                                           bool copy,
                                                       cardinal *len,
                                             objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_reference_count_for_key(table, key, status)
// ---------------------------------------------------------------------------
//
// Returns the  reference count  of the entry stored in <table> for <key>.  If
// no entry exists for <key>,  then  zero  is returned.  Valid entries  always
// have a  reference count  greater than zero.  The status of the operation is
// passed back in <status>,  unless  NULL  was passed in for <status>.

cardinal objm2_kvs_reference_count_for_key(objm2_kvs_table_t table,
                                                    uint32_t key,
                                          objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_release_entry(table, key, status)
// ---------------------------------------------------------------------------
//
// Decrements the reference count of entry stored in <table> for <key> by one.
// If the entry has previously been marked for removal and its reference count
// reaches one  as a result of this release,  then  the entry will be removed.
// The status of the operation  is passed back in <status>,  unless  NULL  was
// passed in for <status>.

void objm2_kvs_release_entry(objm2_kvs_table_t table,
                                      uint32_t key,
                            objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_remove_entry(table, key, status)
// ---------------------------------------------------------------------------
//
// Marks the entry stored in <table> for <key> as removed.  An entry which has
// been marked as removed can no longer be retrieved  and will be removed when
// its  reference count  reaches  zero.  The status of the operation is passed
// back in <status>,  unless  NULL  was passed in for <status>.

void objm2_kvs_remove_entry(objm2_kvs_table_t table,
                                     uint32_t key,
                           objm2_kvs_status_t *status);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_number_of_buckets(table)
// ---------------------------------------------------------------------------
//
// Returns  the number of buckets  of KVS table <table>,  returns zero if NULL
// is passed in for <table>.

cardinal objm2_kvs_number_of_buckets(objm2_kvs_table_t table);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_number_of_entries(table)
// ---------------------------------------------------------------------------
//
// Returns  the number of entries  stored in KVS table <table>,  returns  zero
// if NULL is passed in for <table>.

cardinal objm2_kvs_number_of_entries(objm2_kvs_table_t table);


// ---------------------------------------------------------------------------
// function:  objm2_kvs_dispose_table(table, status)
// ---------------------------------------------------------------------------
//
// Disposes of  KVS table object <table>,  deallocating  all its entries.  The
// table and its entries are disposed of  regardless of any references held to
// any values stored in the table.  The status of the operation is passed back
// in <status>,  unless  NULL  was passed in for <status>.

void objm2_kvs_dispose_table(objm2_kvs_table_t table,
                            objm2_kvs_status_t *status);


#endif /* OBJM2_KVS_H */

// END OF FILE