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-string.h"
#include "m-atomic.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) static inline int atomic_uint_cmp(const atomic_uint *a, const atomic_uint *b)
{ {
unsigned ai = atomic_load(a), bi = atomic_load(b); unsigned ai = atomic_load(a), bi = atomic_load(b);
return ai > bi ? -1 : ai < bi; 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 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 /* Define a directory as a tree where each node contains:
and the name of the directory * the number of lines of the files in this directory,
(Only sort with the number value by disable the sort compare for the string). * 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)))) M_TUPLE_DEF2( dir, (nlines, atomic_uint), (name, m_string_t, M_OPEXTEND(M_STRING_OPLIST, CMP(0))))
#define M_OPL_dir_t() TUPLE_OPLIST(dir, M_OPL_atomic_uint(), M_STRING_OPLIST) /* 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) M_TREE_DEF(tree, dir_t)
@@ -39,17 +49,20 @@ M_TREE_DEF(tree, dir_t)
/* Define the pool of worker threads */ /* Define the pool of worker threads */
worker_t workers; m_worker_t workers;
/* Global synchronous block for all threads */ /* Global synchronous block for all threads */
m_worker_sync_t workers_block; m_worker_sync_t workers_block;
/* Add a specialization of the spawn function for scan_file */ /* Add a specialization of the spawn function for the scan_file function.
M_WORKER_SPAWN_DEF2(scan_file, (parent, tree_it_t, M_POD_OPLIST), (filename, string_t) ) 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 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)) { if (tree_end_p(parent)) {
return tree_emplace_root( tree_tree(parent), 0, dirname); 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 */ /* count the number of end of line character in the buffer */
static unsigned static unsigned
count_eol(const char buffer[], size_t num) count_eol(size_t num, const char buffer[num])
{ {
unsigned count = 0; unsigned count = 0;
for(size_t i = 0; i < num; i++) { for(size_t i = 0; i < num; i++) {
@@ -69,23 +82,23 @@ count_eol(const char buffer[], size_t num)
return count; return count;
} }
/* Test if a filename suffix ends with a C++ or C suffix */
static bool 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") return (m_string_end_with_str_p(filename, ".c")
|| string_end_with_str_p(filename, ".h") || m_string_end_with_str_p(filename, ".h")
|| string_end_with_str_p(filename, ".cpp") || m_string_end_with_str_p(filename, ".cpp")
|| string_end_with_str_p(filename, ".hpp")); || m_string_end_with_str_p(filename, ".hpp"));
} }
/* Scan the file and count its number of lines */
static void 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(m_string_get_cstr(filename), "rt");
FILE *f = fopen(string_get_cstr(filename), "rt");
if (f == NULL) { 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); exit(1);
} }
@@ -95,25 +108,27 @@ scan_file(tree_it_t parent, string_t filename)
size_t num; size_t num;
do { do {
num = fread (buffer, 1, MAX_READ_BUFFER, f); num = fread (buffer, 1, MAX_READ_BUFFER, f);
count += count_eol(buffer, num); count += count_eol(num, buffer);
} while (num == MAX_READ_BUFFER); } while (num == MAX_READ_BUFFER);
fclose(f); fclose(f);
/* Adding the number of lines to the parent directory */ /* Adding the number of lines to the parent directory */
dir_t *d = tree_ref(parent); dir_t *d = tree_ref(parent);
/* atomic add because the scan of files is done in parallel */
atomic_fetch_add( &(*d)->nlines, count ); atomic_fetch_add( &(*d)->nlines, count );
} }
/* Scan the directories recursively for all files */
static void 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); tree_it_t it = add_directory(parent, dirname);
string_t filename; m_string_t filename;
string_init(filename); m_string_init(filename);
DIR *dir = opendir(string_get_cstr(dirname)); DIR *dir = opendir(m_string_get_cstr(dirname));
if (dir == NULL) { 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); exit(1);
} }
@@ -122,20 +137,20 @@ scan_directories(tree_it_t parent, const string_t dirname)
while (entry) { while (entry) {
// Ignore hidden entries (including '.' and '..') // Ignore hidden entries (including '.' and '..')
if (entry->d_name[0] != '.') { if (entry->d_name[0] != '.') {
// Construct the path to the filename // Construct the path to the filename by concatenating dirname, "/" and d_name
string_sets(filename, dirname, "/", entry->d_name); m_string_sets(filename, dirname, "/", entry->d_name);
// Get the property of this filename // Get the property of this filename
struct stat buf; struct stat buf;
int err = stat(string_get_cstr(filename), &buf); int err = stat(m_string_get_cstr(filename), &buf);
if (err != 0) { 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); exit(2);
} }
// Further scanning in function of the kind of entry // Further scanning in function of the kind of entry
if (S_ISDIR(buf.st_mode)) { if (S_ISDIR(buf.st_mode)) {
scan_directories(it, filename); scan_directories(it, filename);
} else { } else if (is_a_c_file(filename)) {
// Spawn a scan of file to available workers // Spawn a scan of file to available workers or run it ourselves
m_worker_spawn_scan_file(workers_block, scan_file, it, filename); 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); closedir(dir);
string_clear(filename); m_string_clear(filename);
} }
/* Consolidate all lines number to the parent directory */
static void static void
consolidate_directories(tree_t directories) 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) ) { 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 *parent = tree_up_ref(it);
dir_t *myself = tree_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 // Add the child number of lines to the parent
atomic_fetch_add_explicit(&(*parent)->nlines, (*myself)->nlines, memory_order_relaxed); 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); tree_sort_child(it);
} }
} }
/* Print the consolidated results on stdout */
static void static void
print_result(tree_t directories) 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) ) { for(tree_it_t it = tree_it(directories) ; !tree_end_p(it) ; tree_next(&it) ) {
int i, depth = tree_depth(it); int i, depth = tree_depth(it);
for(i = 0; i < depth; i++) printf("+"); for(i = 0; i < depth; i++) printf("+");
for( ; i < 8; i++) printf(" "); for( ; i < 8; i++) printf(" ");
const dir_t *d = tree_cref(it); 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[]) int main(int argc, const char *argv[])
{ {
tree_t directories; tree_t directories;
string_t str; m_string_t str;
printf("Count the number of C/C++ lines of code\n"); printf("Count the number of C/C++ lines of code\n");
if (argc < 2) { if (argc < 2) {
@@ -188,7 +205,7 @@ int main(int argc, const char *argv[])
} }
/* Initialize the worker threads */ /* Initialize the worker threads */
worker_init(workers); m_worker_init(workers);
/* Init the tree, reserve for at least the number of max directory /* Init the tree, reserve for at least the number of max directory
and prevent any further increase of allocation: and prevent any further increase of allocation:
@@ -196,20 +213,20 @@ int main(int argc, const char *argv[])
tree_init(directories); tree_init(directories);
tree_reserve(directories, MAX_DIRECTORY); tree_reserve(directories, MAX_DIRECTORY);
tree_lock(directories, true); 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); tree_it_t it = tree_it_end(directories);
/* Main processing */ /* Main processing */
worker_start(workers_block, workers); m_worker_start(workers_block, workers);
scan_directories(it, str); scan_directories(it, str);
worker_sync(workers_block); worker_sync(workers_block);
consolidate_directories(directories); consolidate_directories(directories);
print_result(directories); print_result(directories);
/* Clear everything & quit */ /* Clear everything & quit */
string_clear(str); m_string_clear(str);
tree_clear(directories); tree_clear(directories);
worker_clear(workers); m_worker_clear(workers);
exit(0); exit(0);
} }