forked from enlightenment/efl
eina: add eina_file_map_lines.
This almost replace a loop of fopen/fgets/fclose, but it avoid one memcpy. SVN revision: 70871
This commit is contained in:
parent
2687e46077
commit
f0a9acefa0
|
@ -270,3 +270,7 @@
|
||||||
2012-05-06 Cedric Bail
|
2012-05-06 Cedric Bail
|
||||||
|
|
||||||
* Fix a rounding issue near 1.0 for eina_f32p32_cos and eina_f32p32_sin.
|
* Fix a rounding issue near 1.0 for eina_f32p32_cos and eina_f32p32_sin.
|
||||||
|
|
||||||
|
2012-05-08 Cedric Bail
|
||||||
|
|
||||||
|
* Add eina_file_map_lines to iterate on lines of a mapped file.
|
||||||
|
|
|
@ -5,6 +5,7 @@ Changes since Eina 1.2.0:
|
||||||
|
|
||||||
Additions:
|
Additions:
|
||||||
* Add backtrace support to Eina_Log, use EINA_LOG_BACKTRACE to enable it.
|
* Add backtrace support to Eina_Log, use EINA_LOG_BACKTRACE to enable it.
|
||||||
|
* Add an helper to iterate over line in a mapped file.
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
* Add missing files in the tarball.
|
* Add missing files in the tarball.
|
||||||
|
|
|
@ -98,6 +98,12 @@ typedef struct _Eina_File_Direct_Info Eina_File_Direct_Info;
|
||||||
*/
|
*/
|
||||||
typedef struct _Eina_Stat Eina_Stat;
|
typedef struct _Eina_Stat Eina_Stat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Eina_File_Lines
|
||||||
|
* A typedef to #_Eina_File_Lines.
|
||||||
|
*/
|
||||||
|
typedef struct _Eina_File_Lines Eina_File_Lines;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef Eina_File_Dir_List_Cb
|
* @typedef Eina_File_Dir_List_Cb
|
||||||
* Type for a callback to be called when iterating over the files of a
|
* Type for a callback to be called when iterating over the files of a
|
||||||
|
@ -188,6 +194,20 @@ struct _Eina_Stat
|
||||||
unsigned long int ctimensec;
|
unsigned long int ctimensec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct _Eina_File_Lines
|
||||||
|
* A structure to store information of line
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
struct _Eina_File_Lines
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
const char *start;
|
||||||
|
const char *end;
|
||||||
|
} line;
|
||||||
|
unsigned long long length;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def EINA_FILE_DIR_LIST_CB
|
* @def EINA_FILE_DIR_LIST_CB
|
||||||
* @brief cast to an #Eina_File_Dir_List_Cb.
|
* @brief cast to an #Eina_File_Dir_List_Cb.
|
||||||
|
@ -470,6 +490,19 @@ EAPI void *eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
|
||||||
*/
|
*/
|
||||||
EAPI void eina_file_map_free(Eina_File *file, void *map);
|
EAPI void eina_file_map_free(Eina_File *file, void *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Map line by line in memory efficiently with an Eina_Iterator
|
||||||
|
* @param file The file to run over
|
||||||
|
* @return an Eina_Iterator that will produce @typedef Eina_File_Lines.
|
||||||
|
*
|
||||||
|
* This function return an iterator that will act like fgets without the
|
||||||
|
* useless memcpy. Be aware that once eina_iterator_next has been called,
|
||||||
|
* nothing garanty you that the memory will still be mapped.
|
||||||
|
*
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
EAPI Eina_Iterator *eina_file_map_lines(Eina_File *file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tell if their was an IO error during the life of a mmaped file
|
* @brief Tell if their was an IO error during the life of a mmaped file
|
||||||
*
|
*
|
||||||
|
|
|
@ -41,6 +41,7 @@ void *alloca (size_t);
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#ifdef HAVE_DIRENT_H
|
#ifdef HAVE_DIRENT_H
|
||||||
# include <dirent.h>
|
# include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -1127,6 +1128,139 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator;
|
||||||
|
struct _Eina_Lines_Iterator
|
||||||
|
{
|
||||||
|
Eina_Iterator iterator;
|
||||||
|
|
||||||
|
Eina_File *fp;
|
||||||
|
const char *map;
|
||||||
|
const char *end;
|
||||||
|
|
||||||
|
int boundary;
|
||||||
|
|
||||||
|
Eina_File_Lines current;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* search '\r' and '\n' by preserving cache locality and page locality
|
||||||
|
in doing a search inside 4K boundary.
|
||||||
|
*/
|
||||||
|
static inline const char *
|
||||||
|
_eina_fine_eol(const char *start, int boundary, const char *end)
|
||||||
|
{
|
||||||
|
const char *cr;
|
||||||
|
const char *lf;
|
||||||
|
unsigned long long chunk;
|
||||||
|
|
||||||
|
while (start < end)
|
||||||
|
{
|
||||||
|
chunk = start + boundary < end ? boundary : end - start;
|
||||||
|
cr = memchr(start, '\r', chunk);
|
||||||
|
lf = memchr(start, '\n', chunk);
|
||||||
|
if (cr)
|
||||||
|
{
|
||||||
|
if (lf && lf < cr)
|
||||||
|
return lf + 1;
|
||||||
|
return cr + 1;
|
||||||
|
}
|
||||||
|
else if (lf)
|
||||||
|
return lf + 1;
|
||||||
|
|
||||||
|
start += chunk;
|
||||||
|
boundary = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_eina_file_map_lines_iterator_next(Eina_Lines_Iterator *it, void **data)
|
||||||
|
{
|
||||||
|
const char *eol;
|
||||||
|
|
||||||
|
if (it->current.line.end >= it->end)
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
while ((*it->current.line.end == '\n' || *it->current.line.end == '\r')
|
||||||
|
&& it->current.line.end < it->end)
|
||||||
|
it->current.line.end++;
|
||||||
|
|
||||||
|
if (it->current.line.end == it->end)
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
eol = _eina_fine_eol(it->current.line.end,
|
||||||
|
it->boundary,
|
||||||
|
it->end);
|
||||||
|
it->boundary = (uintptr_t) eol & 0x3FF;
|
||||||
|
if (it->boundary == 0) it->boundary = 4096;
|
||||||
|
|
||||||
|
it->current.line.start = it->current.line.end;
|
||||||
|
while (*eol == '\n' || *eol == '\r')
|
||||||
|
eol--;
|
||||||
|
|
||||||
|
it->current.line.end = eol;
|
||||||
|
it->current.length = eol - it->current.line.start - 1;
|
||||||
|
|
||||||
|
*data = &it->current;
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_File *
|
||||||
|
_eina_file_map_lines_iterator_container(Eina_Lines_Iterator *it)
|
||||||
|
{
|
||||||
|
return it->fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_eina_file_map_lines_iterator_free(Eina_Lines_Iterator *it)
|
||||||
|
{
|
||||||
|
eina_file_map_free(it->fp, (void*) it->map);
|
||||||
|
eina_file_close(it->fp);
|
||||||
|
|
||||||
|
EINA_MAGIC_SET(&it->iterator, 0);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Iterator *
|
||||||
|
eina_file_map_lines(Eina_File *file)
|
||||||
|
{
|
||||||
|
Eina_Lines_Iterator *it;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
|
||||||
|
|
||||||
|
if (file->length == 0) return NULL;
|
||||||
|
|
||||||
|
it = calloc(1, sizeof (Eina_Lines_Iterator));
|
||||||
|
if (!it) return NULL;
|
||||||
|
|
||||||
|
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
|
||||||
|
|
||||||
|
it->map = eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
|
||||||
|
if (!it->map)
|
||||||
|
{
|
||||||
|
free(it);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
eina_lock_take(&file->lock);
|
||||||
|
file->refcount++;
|
||||||
|
eina_lock_release(&file->lock);
|
||||||
|
|
||||||
|
it->fp = file;
|
||||||
|
it->boundary = 4096;
|
||||||
|
it->current.line.start = it->map;
|
||||||
|
it->current.line.end = it->current.line.start;
|
||||||
|
it->current.length = 0;
|
||||||
|
it->end = it->map + it->fp->length;
|
||||||
|
|
||||||
|
it->iterator.version = EINA_ITERATOR_VERSION;
|
||||||
|
it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_map_lines_iterator_next);
|
||||||
|
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_map_lines_iterator_container);
|
||||||
|
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_map_lines_iterator_free);
|
||||||
|
|
||||||
|
return &it->iterator;
|
||||||
|
}
|
||||||
|
|
||||||
EAPI void *
|
EAPI void *
|
||||||
eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
|
eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
|
||||||
unsigned long int offset, unsigned long int length)
|
unsigned long int offset, unsigned long int length)
|
||||||
|
|
Loading…
Reference in New Issue