/* libs/pixelflinger/codeflinger/CodeCache.h
**
** Copyright 2006, 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.
*/


#ifndef ANDROID_CODECACHE_H
#define ANDROID_CODECACHE_H

#include <stdint.h>
#include <pthread.h>
#include <sys/types.h>
#include <cutils/mspace.h>

#include "tinyutils/KeyedVector.h"
#include "tinyutils/smartpointer.h"

namespace android {

// ----------------------------------------------------------------------------

class AssemblyKeyBase {
public:
    virtual ~AssemblyKeyBase() { }
    virtual int compare_type(const AssemblyKeyBase& key) const = 0;
};

template  <typename T>
class AssemblyKey : public AssemblyKeyBase
{
public:
    AssemblyKey(const T& rhs) : mKey(rhs) { }
    virtual int compare_type(const AssemblyKeyBase& key) const {
        const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
        return android::compare_type(mKey, rhs);
    }
private:
    T mKey;
};

// ----------------------------------------------------------------------------

class Assembly
{
public:
                Assembly(size_t size);
    virtual     ~Assembly();

    ssize_t     size() const;
    uint32_t*   base() const;
    ssize_t     resize(size_t size);

    // protocol for sp<>
            void    incStrong(const void* id) const;
            void    decStrong(const void* id) const;
    typedef void    weakref_type;

private:
    static  mspace  getMspace();
            void    ensureMbaseExecutable();

    mutable int32_t     mCount;
            uint32_t*   mBase;
            size_t      mSize;
};

// ----------------------------------------------------------------------------

class CodeCache
{
public:
// pretty simple cache API...
                CodeCache(size_t size);
                ~CodeCache();
    
            sp<Assembly>        lookup(const AssemblyKeyBase& key) const;

            int                 cache(  const AssemblyKeyBase& key,
                                        const sp<Assembly>& assembly);

private:
    // nothing to see here...
    struct cache_entry_t {
        inline cache_entry_t() { }
        inline cache_entry_t(const sp<Assembly>& a, int64_t w)
                : entry(a), when(w) { }
        sp<Assembly>            entry;
        mutable int64_t         when;
    };

    class key_t {
        friend int compare_type(
            const key_value_pair_t<key_t, cache_entry_t>&,
            const key_value_pair_t<key_t, cache_entry_t>&);
        const AssemblyKeyBase* mKey;
    public:
        key_t() { };
        key_t(const AssemblyKeyBase& k) : mKey(&k)  { }
    };

    mutable pthread_mutex_t             mLock;
    mutable int64_t                     mWhen;
    size_t                              mCacheSize;
    size_t                              mCacheInUse;
    KeyedVector<key_t, cache_entry_t>   mCacheData;

    friend int compare_type(
        const key_value_pair_t<key_t, cache_entry_t>&,
        const key_value_pair_t<key_t, cache_entry_t>&);
};

// KeyedVector uses compare_type(), which is more efficient, than
// just using operator < ()
inline int compare_type(
    const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& lhs,
    const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& rhs)
{
    return lhs.key.mKey->compare_type(*(rhs.key.mKey));
}

// ----------------------------------------------------------------------------

}; // namespace android

#endif //ANDROID_CODECACHE_H
