/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed 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.
 */

/*
 * Maintain a table of references.  Used for internal local references,
 * JNI monitor references, and JNI pinned array references.
 *
 * None of the table functions are synchronized.
 */
#ifndef DALVIK_REFERENCETABLE_H_
#define DALVIK_REFERENCETABLE_H_

/*
 * Table definition.
 *
 * The expected common operations are adding a new entry and removing a
 * recently-added entry (usually the most-recently-added entry).
 *
 * If "allocEntries" is not equal to "maxEntries", the table may expand when
 * entries are added, which means the memory may move.  If you want to keep
 * pointers into "table" rather than offsets, use a fixed-size table.
 *
 * (This structure is still somewhat transparent; direct access to
 * table/nextEntry is allowed.)
 */
struct ReferenceTable {
    Object**        nextEntry;          /* top of the list */
    Object**        table;              /* bottom of the list */

    int             allocEntries;       /* #of entries we have space for */
    int             maxEntries;         /* max #of entries allowed */
};

/*
 * Initialize a ReferenceTable.
 *
 * If "initialCount" != "maxCount", the table will expand as required.
 *
 * Returns "false" if table allocation fails.
 */
bool dvmInitReferenceTable(ReferenceTable* pRef, int initialCount,
    int maxCount);

/*
 * Clears out the contents of a ReferenceTable, freeing allocated storage.
 * Does not free "pRef".
 *
 * You must call dvmInitReferenceTable() before you can re-use this table.
 */
void dvmClearReferenceTable(ReferenceTable* pRef);

/*
 * Return the #of entries currently stored in the ReferenceTable.
 */
INLINE size_t dvmReferenceTableEntries(const ReferenceTable* pRef)
{
    return pRef->nextEntry - pRef->table;
}

/*
 * Returns "true" if the table is full.  The table is considered full if
 * we would need to expand it to add another entry.
 */
INLINE size_t dvmIsReferenceTableFull(const ReferenceTable* pRef)
{
    return dvmReferenceTableEntries(pRef) == (size_t)pRef->allocEntries;
}

/*
 * Add a new entry.  "obj" must be a valid non-NULL object reference
 * (though it's okay if it's not fully-formed, e.g. the result from
 * dvmMalloc doesn't have obj->clazz set).
 *
 * Returns "false" if the table is full.
 */
bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj);

/*
 * Determine if "obj" is present in "pRef".  Stops searching when we hit
 * "bottom".  To include the entire table, pass in "pRef->table" as the
 * bottom.
 *
 * Returns NULL if "obj" was not found.
 */
Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** bottom,
    Object* obj);

/*
 * Remove an existing entry.
 *
 * We stop searching for a match after examining the element at "bottom".
 * This is useful when entries are associated with a stack frame.
 *
 * Returns "false" if the entry was not found.
 */
bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** bottom,
    Object* obj);

/*
 * Dump the contents of a reference table to the log file.
 *
 * The caller should lock any external sync before calling.
 */
void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr);

/*
 * Internal function, shared with IndirectRefTable.
 */
void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
    const char* descr);

#endif  // DALVIK_REFERENCETABLE_H_