From 0dcd523e165e0463510c4a6987fb9934f9d9c486 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sat, 14 May 2011 18:04:30 +0300 Subject: [PATCH] * add mu-msg-cache.[ch] for caching MuMsg data --- src/mu-msg-cache.c | 216 +++++++++++++++++++++++++++++++++++++++++++++ src/mu-msg-cache.h | 141 +++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 src/mu-msg-cache.c create mode 100644 src/mu-msg-cache.h diff --git a/src/mu-msg-cache.c b/src/mu-msg-cache.c new file mode 100644 index 00000000..84e33b60 --- /dev/null +++ b/src/mu-msg-cache.c @@ -0,0 +1,216 @@ +/* +** Copyright (C) 2011 Dirk-Jan C. Binnema +** +** This program 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 3, or (at your option) any +** later version. +** +** This program 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 this program; if not, write to the Free Software Foundation, +** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +*/ + +#include +#include + +#include "mu-msg-cache.h" + + +struct _MuMsgCache { + + /* all string properties */ + char *_str[MU_MSG_STRING_FIELD_ID_NUM]; + + time_t _timestamp, _date; + size_t _size; + MuMsgFlags _flags; + MuMsgPrio _prio; + + /* */ + unsigned _cached, _allocated; +}; + +/* _cached and _allocated have a bit for each MuMsgFieldId to remember + * which ones have been cached, and which ones have been allocated. */ + +#define is_allocated(C,MFID) ((C)->_allocated & (1 << (MFID))) +#define is_cached(C,MFID) ((C)->_cached & (1 << (MFID))) + +#define set_allocated(C,MFID) ((C)->_allocated |= (1 << (MFID))) +#define set_cached(C,MFID) ((C)->_cached |= (1 << (MFID))) + +#define reset_allocated(C,MFID) ((C)->_allocated &= ~(1 << (MFID))) +#define reset_cached(C,MFID) ((C)->_cached &= ~(1 << (MFID))) + +MuMsgCache* +mu_msg_cache_new (void) +{ + int i; + MuMsgCache *self; + + self = g_slice_new (MuMsgCache); + + for (i = 0; i != MU_MSG_STRING_FIELD_ID_NUM; ++i) + self->_str[i] = NULL; + + self->_timestamp = (time_t)-1; + self->_size = (size_t)-1; + self->_flags = MU_MSG_FLAG_NONE; + self->_prio = MU_MSG_PRIO_NONE; + self->_date = (time_t)-1; + + self->_cached = 0; + self->_allocated = 0; + + return self; +} + + +void +mu_msg_cache_destroy (MuMsgCache *self) +{ + int i; + + if (!self) + return; + + g_return_if_fail (self); + + for (i = 0; i != MU_MSG_STRING_FIELD_ID_NUM; ++i) + if (is_allocated(self, i)) + g_free (self->_str[i]); + + g_slice_free (MuMsgCache, self); +} + + + +void +cache_set_str (MuMsgCache *self, MuMsgFieldId mfid, char *str, gboolean alloc) +{ + g_return_if_fail (self); + g_return_if_fail (mu_msg_field_is_string(mfid)); + + /* g_warning ("set_str: '%s'=>'%s'; alloc'd: %s; cached: %s", */ + /* mu_msg_field_name(mfid), str ? str : "", */ + /* is_allocated(mfid) ? "yes" : "no", */ + /* is_cached(mfid) ? "yes" : "no"); */ + + /* maybe there was an old, allocated value there already? */ + if (is_allocated(self, mfid)) + g_free (self->_str[mfid]); + + self->_str[mfid] = str; + set_cached (self, mfid); + + if (alloc) + set_allocated (self, mfid); + else + reset_allocated (self, mfid); +} + + + +void +mu_msg_cache_set_str (MuMsgCache *self, MuMsgFieldId mfid, + const char *str) +{ + cache_set_str (self, mfid, (char*)str, FALSE); +} + + +void +mu_msg_cache_set_str_alloc (MuMsgCache *self, MuMsgFieldId mfid, + char *str) +{ + cache_set_str (self, mfid, str, TRUE); +} + +const char* +mu_msg_cache_str (MuMsgCache *cache, MuMsgFieldId mfid) +{ + g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); + return cache->_str[mfid]; +} + + +void +mu_msg_cache_set_num (MuMsgCache *self, MuMsgFieldId mfid, guint64 val) +{ + g_return_if_fail(mu_msg_field_is_numeric(mfid)); + + switch (mfid) { + case MU_MSG_FIELD_ID_DATE: + self->_date = (time_t)val; + break; + case MU_MSG_FIELD_ID_TIMESTAMP: + self->_timestamp = (time_t)val; + break; + case MU_MSG_FIELD_ID_PRIO: + self->_prio = (MuMsgPrio)val; + break; + case MU_MSG_FIELD_ID_FLAGS: + self->_flags = (MuMsgFlags)val; + break; + case MU_MSG_FIELD_ID_SIZE: + self->_size = (size_t)val; + break; + default: g_return_if_reached(); + } + + set_cached (self, mfid); +} + + +gint64 +mu_msg_cache_num (MuMsgCache *self, MuMsgFieldId mfid) +{ + g_return_val_if_fail(mu_msg_field_is_numeric(mfid), -1); + + switch (mfid) { + case MU_MSG_FIELD_ID_DATE: + return (gint64)self->_date; + case MU_MSG_FIELD_ID_TIMESTAMP: + return (gint64)self->_timestamp; + case MU_MSG_FIELD_ID_PRIO: + return (gint64)self->_prio; + case MU_MSG_FIELD_ID_FLAGS: + return (gint64)self->_flags; + case MU_MSG_FIELD_ID_SIZE: + return (gint64)self->_size; + default: g_return_val_if_reached(-1); + } + + set_cached (self, mfid); +} + + +gboolean +mu_msg_cache_cached (MuMsgCache *self, MuMsgFieldId mfid) +{ + g_return_val_if_fail (mfid < MU_MSG_FIELD_ID_NUM, FALSE); + return is_cached(self, mfid) ? TRUE : FALSE; +} + + +void +mu_msg_cache_allocate_all (MuMsgCache *self) +{ + int mfid; + + g_return_if_fail (self); + + for (mfid = 0; mfid != MU_MSG_STRING_FIELD_ID_NUM; ++mfid) { + if (self->_str[mfid] && !is_allocated(self, mfid)) { + self->_str[mfid] = g_strdup (self->_str[mfid]); + set_allocated(self, mfid); + } + } +} diff --git a/src/mu-msg-cache.h b/src/mu-msg-cache.h new file mode 100644 index 00000000..a0e3b37b --- /dev/null +++ b/src/mu-msg-cache.h @@ -0,0 +1,141 @@ +/* +** Copyright (C) 2011 Dirk-Jan C. Binnema +** +** This program 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 3, or (at your option) any +** later version. +** +** This program 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 this program; if not, write to the Free Software Foundation, +** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +*/ + +#ifndef __MU_MSG_CACHE_H__ +#define __MU_MSG_CACHE_H__ + +#include +#include + +/* MuMsgCache caches all values for one specific MuMsg, whether its + * backend is a MuMsgFile or MuMsgDb. The idea is to take all the + * values from the MuMsg so we can release the backend (file or db). + * + * It is specifically designed minimize memory allocations; you can + * either store dynamically-allocated strings, of which the cache will + * take ownership (and g_free in the end), *or* use strings, either + * static or owned elsewhere. In the later case, no copy will be made + * until mu_msg_cache_allocate_all is called + * + * Minimizing allocations in esp. necessary when storing + * search-results as a list of MuMsg instances + */ + +G_BEGIN_DECLS + +struct _MuMsgCache; +typedef struct _MuMsgCache MuMsgCache; + +/** + * initialize the cache + * + * @param self ptr to a cache struct + */ +MuMsgCache *mu_msg_cache_new (void); + +/** + * free the strings in the cache + * + * @param self ptr to a cache struct + */ +void mu_msg_cache_destroy (MuMsgCache *self); + + + +/** + * add a string value to the cache; it will *not* be freed + * + * @param self a cache struc + * @param mfid the MessageFieldId + * @param str the string value to set + */ +void mu_msg_cache_set_str (MuMsgCache *self, MuMsgFieldId mfid, + const char *str); + + + +/** + * add a string value to the cache; the cache takes ownership, and + * will free it when done with it. + * + * @param self a cache struc + * @param mfid the MessageFieldId + * @param str the string value to set + */ +void mu_msg_cache_set_str_alloc (MuMsgCache *self, MuMsgFieldId mfid, + char *str); + +/** + * get a string value from the cache + * + * @param self ptr to a MuMsgCache + * @param mfid the MessageFieldId for a string value + * + * @return the string, or NULL. Don't modify. + */ +const char* mu_msg_cache_str (MuMsgCache *cache, MuMsgFieldId mfid); + + + +/** + * add a numeric value to the cache + * + * @param self a MuMsgCache ptr + * @param mfid the MessageFieldId for a numeric value + * @param val the value + */ +void mu_msg_cache_set_num (MuMsgCache *self, MuMsgFieldId mfid, guint64 val); + + +/** + * get a numeric value from the cache + * + * @param self a MuMsgCache ptr + * @param mfid the MessageFieldId for a numeric value + * + * @return a numeric value + */ +gint64 mu_msg_cache_num (MuMsgCache *self, MuMsgFieldId mfid); + + + +/** + * is the value cached already? + * + * @param self a MuMsgCache ptr + * @param mfid the MessageFieldId for a numeric value + * + * @return TRUE if the value is cached, FALSE otherwise + */ +gboolean mu_msg_cache_cached (MuMsgCache *self, MuMsgFieldId mfid); + + + +/** + * copy all data that was not already owned by the cache + * + * @param self a MuMsgCache ptr + */ +void mu_msg_cache_allocate_all (MuMsgCache *self); + + +G_END_DECLS + +#endif /*__MU_MSG_CACHE_H__*/ +