Add comments to explain what we do

Always use the prefixed version of M*LIB
This commit is contained in:
Patrick Pelissier committed 2023-02-18 09:58:30 +01:00
1 parent 55b745b916
commit bf6c1341b3
1 file changed
+63 -46
+63 -46
View File
@@ -10,24 +10,34 @@
#include "m-string.h"
#include "m-atomic.h"
/* Sort the atomic unsigned int with the biggest value first. */
/* Define the comparison function for atomic_uint type
to sort the atomic unsigned int with the biggest value first. */
static inline int atomic_uint_cmp(const atomic_uint *a, const atomic_uint *b)
{
unsigned ai = atomic_load(a), bi = atomic_load(b);
return ai > bi ? -1 : ai < bi;
}
/* Disable HASH for atomic as the default hash method won't work */
/* Define the oplist for atomic_uint and register it globally.
This oplist extends the basic oplist by:
* disabling HASH for atomic as the default hash method won't work.
* providing the methods for CMP, INIT_SET and SET operators (with their API adaptator) */
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)), INIT_SET(API_2(atomic_store)), SET(API_2(atomic_store)))
/* Define a directory as the number of lines of the files in this directory
and the name of the directory
(Only sort with the number value by disable the sort compare for the string).
/* Define a directory as a tree where each node contains:
* the number of lines of the files in this directory,
* and the name of the directory/
Since we want to sort with the number of lines only, we extend the oplist of a string by disabling the compare method.
So first, let's define the node as a tuple of such elements:
*/
TUPLE_DEF2( dir, (nlines, atomic_uint), (name, string_t, M_OPEXTEND(STRING_OPLIST, CMP(0))))
#define M_OPL_dir_t() TUPLE_OPLIST(dir, M_OPL_atomic_uint(), M_STRING_OPLIST)
M_TUPLE_DEF2( dir, (nlines, atomic_uint), (name, m_string_t, M_OPEXTEND(M_STRING_OPLIST, CMP(0))))
/* Register globally the oplist of this tuple */
#define M_OPL_dir_t() M_TUPLE_OPLIST(dir, M_OPL_atomic_uint(), M_STRING_OPLIST)
/* A hierarchical tree of directory */
/* Define a hierarchical tree of directory.
Note that it will use the globally registered oplist associated to dir_t to use it */
M_TREE_DEF(tree, dir_t)
@@ -39,17 +49,20 @@ M_TREE_DEF(tree, dir_t)
/* Define the pool of worker threads */
worker_t workers;
m_worker_t workers;
/* Global synchronous block for all threads */
m_worker_sync_t workers_block;
/* Add a specialization of the spawn function for scan_file */
M_WORKER_SPAWN_DEF2(scan_file, (parent, tree_it_t, M_POD_OPLIST), (filename, string_t) )
/* Add a specialization of the spawn function for the scan_file function.
This functions takes as input an iterator of a tree (treated as a POD data),
and a file name */
M_WORKER_SPAWN_DEF2(scan_file, (parent, tree_it_t, M_POD_OPLIST), (filename, m_string_t) )
/* Add either the root node or a child to parent in function of the existence of parent */
static tree_it_t
add_directory(tree_it_t parent, const string_t dirname)
add_directory(tree_it_t parent, const m_string_t dirname)
{
if (tree_end_p(parent)) {
return tree_emplace_root( tree_tree(parent), 0, dirname);
@@ -60,7 +73,7 @@ add_directory(tree_it_t parent, const string_t dirname)
/* count the number of end of line character in the buffer */
static unsigned
count_eol(const char buffer[], size_t num)
count_eol(size_t num, const char buffer[num])
{
unsigned count = 0;
for(size_t i = 0; i < num; i++) {
@@ -69,23 +82,23 @@ count_eol(const char buffer[], size_t num)
return count;
}
/* Test if a filename suffix ends with a C++ or C suffix */
static bool
is_a_c_file(const string_t filename)
is_a_c_file(const m_string_t filename)
{
return (string_end_with_str_p(filename, ".c")
|| string_end_with_str_p(filename, ".h")
|| string_end_with_str_p(filename, ".cpp")
|| string_end_with_str_p(filename, ".hpp"));
return (m_string_end_with_str_p(filename, ".c")
|| m_string_end_with_str_p(filename, ".h")
|| m_string_end_with_str_p(filename, ".cpp")
|| m_string_end_with_str_p(filename, ".hpp"));
}
/* Scan the file and count its number of lines */
static void
scan_file(tree_it_t parent, string_t filename)
scan_file(tree_it_t parent, m_string_t filename)
{
if (!is_a_c_file(filename)) return;
FILE *f = fopen(string_get_cstr(filename), "rt");
FILE *f = fopen(m_string_get_cstr(filename), "rt");
if (f == NULL) {
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", string_get_cstr(filename) );
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", m_string_get_cstr(filename) );
exit(1);
}
@@ -95,25 +108,27 @@ scan_file(tree_it_t parent, string_t filename)
size_t num;
do {
num = fread (buffer, 1, MAX_READ_BUFFER, f);
count += count_eol(buffer, num);
count += count_eol(num, buffer);
} while (num == MAX_READ_BUFFER);
fclose(f);
/* Adding the number of lines to the parent directory */
dir_t *d = tree_ref(parent);
/* atomic add because the scan of files is done in parallel */
atomic_fetch_add( &(*d)->nlines, count );
}
/* Scan the directories recursively for all files */
static void
scan_directories(tree_it_t parent, const string_t dirname)
scan_directories(tree_it_t parent, const m_string_t dirname)
{
tree_it_t it = add_directory(parent, dirname);
string_t filename;
string_init(filename);
DIR *dir = opendir(string_get_cstr(dirname));
m_string_t filename;
m_string_init(filename);
DIR *dir = opendir(m_string_get_cstr(dirname));
if (dir == NULL) {
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", string_get_cstr(dirname) );
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", m_string_get_cstr(dirname) );
exit(1);
}
@@ -122,20 +137,20 @@ scan_directories(tree_it_t parent, const string_t dirname)
while (entry) {
// Ignore hidden entries (including '.' and '..')
if (entry->d_name[0] != '.') {
// Construct the path to the filename
string_sets(filename, dirname, "/", entry->d_name);
// Construct the path to the filename by concatenating dirname, "/" and d_name
m_string_sets(filename, dirname, "/", entry->d_name);
// Get the property of this filename
struct stat buf;
int err = stat(string_get_cstr(filename), &buf);
int err = stat(m_string_get_cstr(filename), &buf);
if (err != 0) {
fprintf(stderr, "ERROR: Cannot stat %s\n", string_get_cstr(filename));
fprintf(stderr, "ERROR: Cannot stat %s\n", m_string_get_cstr(filename));
exit(2);
}
// Further scanning in function of the kind of entry
if (S_ISDIR(buf.st_mode)) {
scan_directories(it, filename);
} else {
// Spawn a scan of file to available workers
} else if (is_a_c_file(filename)) {
// Spawn a scan of file to available workers or run it ourselves
m_worker_spawn_scan_file(workers_block, scan_file, it, filename);
}
}
@@ -144,13 +159,14 @@ scan_directories(tree_it_t parent, const string_t dirname)
}
closedir(dir);
string_clear(filename);
m_string_clear(filename);
}
/* Consolidate all lines number to the parent directory */
static void
consolidate_directories(tree_t directories)
{
// Scan all entries, first the childreen, then the parent
// Scan all entries, first the children, then the parent
for(tree_it_t it = tree_it_post(directories) ; !tree_end_p(it) ; tree_next_post(&it) ) {
dir_t *parent = tree_up_ref(it);
dir_t *myself = tree_ref(it);
@@ -158,28 +174,29 @@ consolidate_directories(tree_t directories)
// Add the child number of lines to the parent
atomic_fetch_add_explicit(&(*parent)->nlines, (*myself)->nlines, memory_order_relaxed);
}
// Sort the data of the childreen by the number of lines
// Sort the data of the children by the number of lines
tree_sort_child(it);
}
}
/* Print the consolidated results on stdout */
static void
print_result(tree_t directories)
{
// Scan all entries, first the parent, then the childreen
// Scan all entries, first the parent, then the children
for(tree_it_t it = tree_it(directories) ; !tree_end_p(it) ; tree_next(&it) ) {
int i, depth = tree_depth(it);
for(i = 0; i < depth; i++) printf("+");
for( ; i < 8; i++) printf(" ");
const dir_t *d = tree_cref(it);
printf("%6u %s\n", (unsigned) (*d)->nlines, string_get_cstr( (*d)->name ) );
printf("%6u %s\n", (unsigned) (*d)->nlines, m_string_get_cstr( (*d)->name ) );
}
}
int main(int argc, const char *argv[])
{
tree_t directories;
string_t str;
m_string_t str;
printf("Count the number of C/C++ lines of code\n");
if (argc < 2) {
@@ -188,7 +205,7 @@ int main(int argc, const char *argv[])
}
/* Initialize the worker threads */
worker_init(workers);
m_worker_init(workers);
/* Init the tree, reserve for at least the number of max directory
and prevent any further increase of allocation:
@@ -196,20 +213,20 @@ int main(int argc, const char *argv[])
tree_init(directories);
tree_reserve(directories, MAX_DIRECTORY);
tree_lock(directories, true);
string_init_set_str(str, argv[1]);
m_string_init_set_cstr(str, argv[1]);
tree_it_t it = tree_it_end(directories);
/* Main processing */
worker_start(workers_block, workers);
m_worker_start(workers_block, workers);
scan_directories(it, str);
worker_sync(workers_block);
consolidate_directories(directories);
print_result(directories);
/* Clear everything & quit */
string_clear(str);
m_string_clear(str);
tree_clear(directories);
worker_clear(workers);
m_worker_clear(workers);
exit(0);
}