<commit_before>/* Creative Commons has made the contents of this file
 * available under a CC-GNU-LGPL license:
 *
 * http://creativecommons.org/licenses/LGPL/2.1/
 *
 * A copy of the full license can be found as part of this
 * distribution in the file COPYING.
 *
 * You may use the liblicense software in accordance with the
 * terms of that license. You agree that you are solely 
 * responsible for your use of the liblicense software and you
 * represent and warrant to Creative Commons that your use
 * of the liblicense software will comply with the CC-GNU-LGPL.
 *
 * Copyright 2007, Creative Commons, www.creativecommons.org.
 * Copyright 2007, <NAME>
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <liblicense.h>

struct _ll_license_chooser_t {
	char **attributes;
	int num_attributes;

	/* This is the meat of the license chooser.  It is an array of linked-lists of licenses, where each slot holds all the licenses which match a given combination of license flags.  The array holds all possible combinations of attributes.
	 *
	 * Finding the matching index based on a set of flags involves traversing this structure in a tree-like manner.  A tree built for searching based on the Attribution and CommercialUse attributes is structured like this example:
	 *
	 *                                                  root
	 *                           /               |            |              \
	 * Attribution  :          P                 R           Pr              U
	 *                    /  |   |   \      / |   |  \    / |  |  \       / |  |  \
	 * CommercialUse:    P   R   Pr  U     P  R  Pr  U   P  R  Pr  U     P  R  Pr  U
	 * Indices in
	 *  license_list:    0   1   2   3    4   5  6   7   8  9  10  11   12 13  14 15 
	 *
	 * In the example above, the list of licenses that require (R) Attribution and prohibit (Pr) CommercialUse
	 * is found at license_list[6].
	 *
	 * Such a structure allows easy hierarchical traversion.  Ignore the indices above and instead
	 * index the tree as a d-heap (where d=N_STATES). A node's left-most child is always (node_index-N_STATES+2)*N_STATES.
	 * N_STATES is 4 for P, R Pr, and U.
	 */
	ll_license_list_t **license_list;

	uri_t *all_licenses; 	/* to avoid copying each license, store the license entire license list
												 * and free them all in one go when we destroy the license_chooser
												 */
};

#define LL_ATTR_PERMITS 			0
#define LL_ATTR_REQUIRES 		1
#define LL_ATTR_PROHIBITS 		2
#define LL_ATTR_UNSPECIFIED 	3

/* Note: if N_STATES changes, lines like these also need to be adapted:
 * 1 << (num_attributes * 2)
 * which are optimized from pow(N_STATES,num_attributes)
 * due to the fact that 4 is a power of 2
 */
#define N_STATES 4

/* Returns the index of the first node of the heap at the given height */
int indexAt( int height )
{
	int h = 0;
	int i = N_STATES;
	int counter = 1;

	while (h < height) {
		h++;
		counter *= N_STATES;
		i += counter;
	}
	return i - counter;
}

/* Returns the total number of nodes in the heap built for searching on the given number of attributes */
int heap_size( int num_attributes )
{
	int h = 0;
	int i = N_STATES;
	int counter = 1;

	while (h < num_attributes) {
		h++;
		counter *= N_STATES;
		i += counter;
	}
	return i;
}

/* Recursively traverse the license heap, increasing the appropriate index in license_hits.  When the traversal is complete, the license which has <num_attribute> hits is the matched license.
 *
 * For example, one call of iterate_children will increase license_hits[] for all licenses that prohibit CommercialUse.  On the next call to iterate_children, all licenses that require Attribution are increased.  Using the above tree in this example, first, license_hits[2,6,10,14] are all increased to 1.  Then the second call increases license_hits[4,5,6,7].  license_hits[6] is now 2, meaning we've matched the licenses at that index.
 */
void iterate_children( int *license_hits, int index, int height, int heap_size )
{
	int leftChild = (index-N_STATES+2)*N_STATES;

	if (leftChild >= heap_size) { /* we've hit a leaf node, where the licenses are */
		/* the array tracks leaf nodes, while the heap tracks all nodes */
		int arrayIndex = index-indexAt(height);
		license_hits[arrayIndex] += 1;
		return;
	}

	int i = 0;
	while ( i<N_STATES ) {
		iterate_children( license_hits, leftChild+i, height+1, heap_size );
		i++;
	}
}

int attribute_index( const char **attributes, char *attr, int num_attributes )
{
	int i;
	for (i=0; i<num_attributes; ++i) {
		if ( strcmp(attr,attributes[i]) == 0 )
			return i+1;
	}
	return -1;
}

int ll_attribute_flag( ll_license_chooser_t *license_chooser, const char *attr )
{
	int i;
	for (i=0; i<license_chooser->num_attributes; ++i) {
		if (strcmp(attr,license_chooser->attributes[i])==0) {
			return (1<<i);
		}
	}
	return -1;
}

const ll_license_list_t* ll_get_licenses_from_flags( ll_license_chooser_t *license_chooser, int permits, int requires, int prohibits )
{
	/* Traverse the down the tree until we get to the right leaf.  Each pass in the for-loop traverses down one level
	 * of the tree.<commit_msg>Add static keyword to prevent exporting non-ll_* symbols.  Patch by <NAME> (<EMAIL>)<commit_after>/* Creative Commons has made the contents of this file
 * available under a CC-GNU-LGPL license:
 *
 * http://creativecommons.org/licenses/LGPL/2.1/
 *
 * A copy of the full license can be found as part of this
 * distribution in the file COPYING.
 *
 * You may use the liblicense software in accordance with the
 * terms of that license. You agree that you are solely 
 * responsible for your use of the liblicense software and you
 * represent and warrant to Creative Commons that your use
 * of the liblicense software will comply with the CC-GNU-LGPL.
 *
 * Copyright 2007, Creative Commons, www.creativecommons.org.
 * Copyright 2007, <NAME>
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <liblicense.h>

struct _ll_license_chooser_t {
	char **attributes;
	int num_attributes;

	/* This is the meat of the license chooser.  It is an array of linked-lists of licenses, where each slot holds all the licenses which match a given combination of license flags.  The array holds all possible combinations of attributes.
	 *
	 * Finding the matching index based on a set of flags involves traversing this structure in a tree-like manner.  A tree built for searching based on the Attribution and CommercialUse attributes is structured like this example:
	 *
	 *                                                  root
	 *                           /               |            |              \
	 * Attribution  :          P                 R           Pr              U
	 *                    /  |   |   \      / |   |  \    / |  |  \       / |  |  \
	 * CommercialUse:    P   R   Pr  U     P  R  Pr  U   P  R  Pr  U     P  R  Pr  U
	 * Indices in
	 *  license_list:    0   1   2   3    4   5  6   7   8  9  10  11   12 13  14 15 
	 *
	 * In the example above, the list of licenses that require (R) Attribution and prohibit (Pr) CommercialUse
	 * is found at license_list[6].
	 *
	 * Such a structure allows easy hierarchical traversion.  Ignore the indices above and instead
	 * index the tree as a d-heap (where d=N_STATES). A node's left-most child is always (node_index-N_STATES+2)*N_STATES.
	 * N_STATES is 4 for P, R Pr, and U.
	 */
	ll_license_list_t **license_list;

	uri_t *all_licenses; 	/* to avoid copying each license, store the license entire license list
												 * and free them all in one go when we destroy the license_chooser
												 */
};

#define LL_ATTR_PERMITS 			0
#define LL_ATTR_REQUIRES 		1
#define LL_ATTR_PROHIBITS 		2
#define LL_ATTR_UNSPECIFIED 	3

/* Note: if N_STATES changes, lines like these also need to be adapted:
 * 1 << (num_attributes * 2)
 * which are optimized from pow(N_STATES,num_attributes)
 * due to the fact that 4 is a power of 2
 */
#define N_STATES 4

/* Returns the index of the first node of the heap at the given height */
static int indexAt( int height )
{
	int h = 0;
	int i = N_STATES;
	int counter = 1;

	while (h < height) {
		h++;
		counter *= N_STATES;
		i += counter;
	}
	return i - counter;
}

/* Returns the total number of nodes in the heap built for searching on the given number of attributes */
static int heap_size( int num_attributes )
{
	int h = 0;
	int i = N_STATES;
	int counter = 1;

	while (h < num_attributes) {
		h++;
		counter *= N_STATES;
		i += counter;
	}
	return i;
}

/* Recursively traverse the license heap, increasing the appropriate index in license_hits.  When the traversal is complete, the license which has <num_attribute> hits is the matched license.
 *
 * For example, one call of iterate_children will increase license_hits[] for all licenses that prohibit CommercialUse.  On the next call to iterate_children, all licenses that require Attribution are increased.  Using the above tree in this example, first, license_hits[2,6,10,14] are all increased to 1.  Then the second call increases license_hits[4,5,6,7].  license_hits[6] is now 2, meaning we've matched the licenses at that index.
 */
static void iterate_children( int *license_hits, int index, int height, int heap_size )
{
	int leftChild = (index-N_STATES+2)*N_STATES;

	if (leftChild >= heap_size) { /* we've hit a leaf node, where the licenses are */
		/* the array tracks leaf nodes, while the heap tracks all nodes */
		int arrayIndex = index-indexAt(height);
		license_hits[arrayIndex] += 1;
		return;
	}

	int i = 0;
	while ( i<N_STATES ) {
		iterate_children( license_hits, leftChild+i, height+1, heap_size );
		i++;
	}
}

static int attribute_index( const char **attributes, char *attr, int num_attributes )
{
	int i;
	for (i=0; i<num_attributes; ++i) {
		if ( strcmp(attr,attributes[i]) == 0 )
			return i+1;
	}
	return -1;
}

int ll_attribute_flag( ll_license_chooser_t *license_chooser, const char *attr )
{
	int i;
	for (i=0; i<license_chooser->num_attributes; ++i) {
		if (strcmp(attr,license_chooser->attributes[i])==0) {
			return (1<<i);
		}
	}
	return -1;
}

const ll_license_list_t* ll_get_licenses_from_flags( ll_license_chooser_t *license_chooser, int permits, int requires, int prohibits )
{
	/* Traverse the down the tree until we get to the right leaf.  Each pass in the for-loop traverses down one level
	 * of the tree.
{'fraction_non_alphanumeric': 0.08290705530354213, 'fraction_numerical': 0.014091303928192259, 'mean_word_length': 2.911664779161948, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5368121', 'n_tokens_mistral': 3446, 'n_tokens_neox': 3185, 'n_words': 1302}