<commit_before>/* ENESIM - Direct Rendering Library
 * Copyright (C) 2007-2011 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.
 * If not, see <http://www.gnu.org/licenses/>.
 */
#include "enesim_private.h"
#include "libargb.h"

#include "enesim_main.h"
#include "enesim_eina.h"
#include "enesim_error.h"
#include "enesim_color.h"
#include "enesim_rectangle.h"
#include "enesim_matrix.h"
#include "enesim_pool.h"
#include "enesim_buffer.h"
#include "enesim_surface.h"
#include "enesim_compositor.h"
#include "enesim_renderer.h"

#include "enesim_surface_private.h"
#include "enesim_renderer_private.h"
/**
 * @todo
 * - Add a way to get/set such description
 * - Change every internal struct on Enesim to have the correct prefix
 *   looks like we are having issues with mingw
 * - We have some overlfow on the coordinates whenever we want to trasnlate or
 *   transform bounds, we need to fix the maximum and minimum for a
 *   coordinate and length
 *
 * - Maybe checking the flags for every origin/value set is too much
 * another option is to make every renderer responsable of changing the origin/scale/etc
 * if the owned renderer handles that
 */
/*============================================================================*
 *                                  Local                                     *
 *============================================================================*/
#define ENESIM_LOG_DEFAULT enesim_log_renderer

#define ENESIM_MAGIC_RENDERER 0xe7e51420
#define ENESIM_MAGIC_CHECK_RENDERER(d)\
	do {\
		if (!EINA_MAGIC_CHECK(d, ENESIM_MAGIC_RENDERER))\
			EINA_MAGIC_FAIL(d, ENESIM_MAGIC_RENDERER);\
	} while(0)

typedef struct _Enesim_Renderer_Factory
{
	int id;
} Enesim_Renderer_Factory;

static Eina_Hash *_factories = NULL;

static void _enesim_renderer_factory_free(void *data)
{
	Enesim_Renderer_Factory *f = data;
	free(f);
}
/*----------------------------------------------------------------------------*
 *                     Functions to transform the bounds                      *
 *----------------------------------------------------------------------------*/
static inline void _enesim_renderer_bounds(Enesim_Renderer *r, Enesim_Rectangle *bounds,
		const Enesim_Renderer_State *current,
		const Enesim_Renderer_State *past)
{
	if (r->descriptor.bounds)
	{
		const Enesim_Renderer_State *states[ENESIM_RENDERER_STATES];

		states[ENESIM_STATE_CURRENT] = current;
		states[ENESIM_STATE_PAST] = past;
		r->descriptor.bounds(r, states, bounds);
	}
	else
	{
		enesim_rectangle_coords_from(bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	}
}

static inline void _enesim_renderer_destination_bounds(Enesim_Renderer *r,
		Eina_Rectangle *bounds, const Enesim_Renderer_State *current,
		const Enesim_Renderer_State *past)
{
	if (r->descriptor.destination_bounds)
	{
		const Enesim_Renderer_State *states[ENESIM_RENDERER_STATES];

		states[ENESIM_STATE_CURRENT] = current;
		states[ENESIM_STATE_PAST] = past;

		r->descriptor.destination_bounds(r, states, bounds);
	}
	else
	{
		eina_rectangle_coords_from(bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	}
}

static void _draw_internal(Enesim_Renderer *r, Enesim_Surface *s,
		Eina_Rectangle *area, int x, int y)
{
	Enesim_Backend b;

	enesim_surface_lock(s, EINA_TRUE);
	b = enesim_surface_backend_get(s);
	switch (b)
	{
		case ENESIM_BACKEND_SOFTWARE:
		enesim_renderer_sw_draw_area(r, s, area, x, y);
		break;

		case ENESIM_BACKEND_OPENCL:
#if BUILD_OPENCL
		enesim_renderer_opencl_draw(r, s, area, x, y);
#endif
		break;

		case ENESIM_BACKEND_OPENGL:
#if BUILD_OPENGL
		enesim_renderer_opengl_draw(r, s, area, x, y);
#endif
		break;

		default:
		WRN("Backend not supported %d", b);
		break;
	}
	enesim_surface_unlock(s);
}

static void _draw_list_internal(Enesim_Renderer *r, Enesim_Surface *s,
		Eina_Rectangle *area,
		Eina_List *clips, int x, int y)
{
	Enesim_Backend b;
	Eina_Rectangle *clip;
	Eina_List *l;

	enesim_surface_lock(s, EINA_TRUE);
	b = enesim_surface_backend_get(s);
	switch (b)
	{
		case ENESIM_BACKEND_SOFTWARE:
		EINA_LIST_FOREACH(clips, l, clip)
		{
			Eina_Rectangle final;

			final = *clip;
			if (!eina_rectangle_intersection(&final, area))
				continue;
			enesim_renderer_sw_draw_area(r, s, &final, x, y);
		}
		break;

		case ENESIM_BACKEND_OPENGL:
#if BUILD_OPENGL
		EINA_LIST_FOREACH(clips, l, clip)
		{
			Eina_Rectangle final;

			final = *clip;
			if (!eina_rectangle_intersection(&final, area))
				continue;
			enesim_renderer_opengl_draw(r, s, &final, x, y);
		}
#endif
		break;

		default:
		WRN("Backend not supported %d", b);
		break;
	}
	enesim_surface_unlock(s);
}

static inline void _surface_bounds(Enesim_Surface *s, Eina_Rectangle *bounds)
{
	bounds->x = 0;
	bounds->y = 0;
	enesim_surface_size_get(s, &bounds->w, &bounds->h);
}

static void _enesim_renderer_factory_setup(Enesim_Renderer *r)
{
	Enesim_Renderer_Factory *f;
	char renderer_name[PATH_MAX];
	const char *descriptor_name = NULL;

	if (!_factories) return;
	if (r->descriptor.name)
		descriptor_name = r->descriptor.name(r);
	if (!descriptor_name)
		descriptor_name = "unknown";
	f = eina_hash_find(_factories, descriptor_name);
	if (!f)
	{
		f = calloc(1, sizeof(Enesim_Renderer_Factory));
		eina_hash_add(_factories, descriptor_name, f);
	}
	/* assign a new name for it automatically */
	snprintf(renderer_name, PATH_MAX, "%s%d", descriptor_name, f->id++);
	enesim_renderer_name_set(r, renderer_name);
}

static Eina_Bool _enesim_renderer_common_changed(Enesim_Renderer *r)
{
	/* the visibility */
	if (r->current.visibility != r->past.visibility)
	{
		return EINA_TRUE;
	}
	/* the rop */
	if (r->current.rop != r->past.rop)
	{
		return EINA_TRUE;
	}
	/* the color */
	if (r->current.color != r->past.color)
	{
		return EINA_TRUE;
	}
	/* the mask */
	if (r->current.mask && !r->past.mask)
		return EINA_TRUE;
	if (!r->current.mask && r->past.mask)
		return EINA_TRUE;
	if (r->current.mask)
	{
		if (enesim_renderer_has_changed(r->current.mask))
		{
			DBG("The mask renderer %s has changed", r->name);
			return EINA_TRUE;
		}
	}
	/* the origin */
	if (r->current.ox != r->past.ox || r->current.oy != r->past.oy)
	{
		return EINA_TRUE;
	}
	/* the transformation */
	if (r->current.transformation_type != r->past.transformation_type)
	{
		return EINA_TRUE;
	}

	if (!enesim_matrix_is_equal(&r->current.transformation, &r->past.transformation))
	{
		return EINA_TRUE;
	}

	return EINA_FALSE;
}
/*============================================================================*
 *                                 Global                                     *
 *============================================================================*/
void enesim_renderer_init(void)
{
	_factories = eina_hash_string_superfast_new(
			_enesim_renderer_factory_free);
	enesim_renderer_sw_init();
#if BUILD_OPENGL
	enesim_renderer_opengl_init();
#endif
}

void enesim_renderer_shutdown(void)
{
	eina_hash_free(_factories);
	_factories = NULL;
	enesim_renderer_sw_shutdown();
}

/* FIXME export this */
void * enesim_renderer_backend_data_get(Enesim_Renderer *r, Enesim_Backend b)
{
	return r->backend_data[b];
}

void enesim_renderer_backend_data_set(Enesim_Renderer *r, Enesim_Backend b, void *data)
{
	r->backend_data[b] = data;
}
/*============================================================================*
 *                                   API                                      *
 *============================================================================*/
/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI Enesim_Renderer * enesim_renderer_new(Enesim_Renderer_Descriptor
		*descriptor, void *data)
{
	Enesim_Renderer *r;

	if (!descriptor) return NULL;
	if (descriptor->version > ENESIM_RENDERER_API) {
		ERR("API version %d is greater than %d", descriptor->version, ENESIM_RENDERER_API);
		return NULL;
	}

	r = calloc(1, sizeof(Enesim_Renderer));
	/* first check the passed in functions */
	if (!descriptor->is_inside) WRN("No is_inside() function available");
	if (!descriptor->bounds) WRN("No bounding() function available");
	if (!descriptor->flags) WRN("No flags() function available");
	if (!descriptor->sw_setup) WRN("No sw_setup() function available");
	if (!descriptor->sw_cleanup) WRN("No sw_cleanup() function available");
	if (!descriptor->free) WRN("No free() function available");
	r->descriptor = *descriptor;
	r->data = data;
	/* now initialize the renderer common properties */
	EINA_MAGIC_SET(r, ENESIM_MAGIC_RENDERER);
	/* common properties */
	r->current.visibility = r->past.visibility = EINA_TRUE;
	r->current.ox = r->past.ox = 0;
	r->current.oy = r->past.oy = 0;
	r->current.color = r->past.color = ENESIM_COLOR_FULL;
	r->current.rop = r->past.rop = ENESIM_FILL;
	enesim_matrix_identity(&r->current.transformation);
	enesim_matrix_identity(&r->past.transformation);
	r->current.transformation_type = ENESIM_MATRIX_IDENTITY;
	r->past.transformation_type = ENESIM_MATRIX_IDENTITY;
	/* private stuff */
	r->current_flags = 0;
	enesim_rectangle_coords_from(&r->past_bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	eina_rectangle_coords_from(&r->past_destination_bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	r->prv_data = eina_hash_string_superfast_new(NULL);
	eina_lock_new(&r->lock);
	/* always set the first reference */
	r = enesim_renderer_ref(r);
	_enesim_renderer_factory_setup(r);

	return r;
}

/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI void * enesim_renderer_data_get(Enesim_Renderer *r)
{
	ENESIM_MAGIC_CHECK_RENDERER(r);

	return r->data;
}

/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI Enesim_Renderer * enesim_renderer_ref(Enesim_Renderer *r)
{
	ENESIM_MAGIC_CHECK_RENDERER(r);
	r->ref++;
	return r;
}

/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI void enesim_renderer_unref(Enesim_Renderer *r)
{
	ENESIM_MAGIC_CHECK_RENDERER(r);
	r->ref--;
	if (!r->ref)
	{
		if (r->descriptor.free)
			r->descriptor.free(r);<commit_msg>Free the name<commit_after>/* ENESIM - Direct Rendering Library
 * Copyright (C) 2007-2011 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.
 * If not, see <http://www.gnu.org/licenses/>.
 */
#include "enesim_private.h"
#include "libargb.h"

#include "enesim_main.h"
#include "enesim_eina.h"
#include "enesim_error.h"
#include "enesim_color.h"
#include "enesim_rectangle.h"
#include "enesim_matrix.h"
#include "enesim_pool.h"
#include "enesim_buffer.h"
#include "enesim_surface.h"
#include "enesim_compositor.h"
#include "enesim_renderer.h"

#include "enesim_surface_private.h"
#include "enesim_renderer_private.h"
/**
 * @todo
 * - Add a way to get/set such description
 * - Change every internal struct on Enesim to have the correct prefix
 *   looks like we are having issues with mingw
 * - We have some overlfow on the coordinates whenever we want to trasnlate or
 *   transform bounds, we need to fix the maximum and minimum for a
 *   coordinate and length
 *
 * - Maybe checking the flags for every origin/value set is too much
 * another option is to make every renderer responsable of changing the origin/scale/etc
 * if the owned renderer handles that
 */
/*============================================================================*
 *                                  Local                                     *
 *============================================================================*/
#define ENESIM_LOG_DEFAULT enesim_log_renderer

#define ENESIM_MAGIC_RENDERER 0xe7e51420
#define ENESIM_MAGIC_CHECK_RENDERER(d)\
	do {\
		if (!EINA_MAGIC_CHECK(d, ENESIM_MAGIC_RENDERER))\
			EINA_MAGIC_FAIL(d, ENESIM_MAGIC_RENDERER);\
	} while(0)

typedef struct _Enesim_Renderer_Factory
{
	int id;
} Enesim_Renderer_Factory;

static Eina_Hash *_factories = NULL;

static void _enesim_renderer_factory_free(void *data)
{
	Enesim_Renderer_Factory *f = data;
	free(f);
}
/*----------------------------------------------------------------------------*
 *                     Functions to transform the bounds                      *
 *----------------------------------------------------------------------------*/
static inline void _enesim_renderer_bounds(Enesim_Renderer *r, Enesim_Rectangle *bounds,
		const Enesim_Renderer_State *current,
		const Enesim_Renderer_State *past)
{
	if (r->descriptor.bounds)
	{
		const Enesim_Renderer_State *states[ENESIM_RENDERER_STATES];

		states[ENESIM_STATE_CURRENT] = current;
		states[ENESIM_STATE_PAST] = past;
		r->descriptor.bounds(r, states, bounds);
	}
	else
	{
		enesim_rectangle_coords_from(bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	}
}

static inline void _enesim_renderer_destination_bounds(Enesim_Renderer *r,
		Eina_Rectangle *bounds, const Enesim_Renderer_State *current,
		const Enesim_Renderer_State *past)
{
	if (r->descriptor.destination_bounds)
	{
		const Enesim_Renderer_State *states[ENESIM_RENDERER_STATES];

		states[ENESIM_STATE_CURRENT] = current;
		states[ENESIM_STATE_PAST] = past;

		r->descriptor.destination_bounds(r, states, bounds);
	}
	else
	{
		eina_rectangle_coords_from(bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	}
}

static void _draw_internal(Enesim_Renderer *r, Enesim_Surface *s,
		Eina_Rectangle *area, int x, int y)
{
	Enesim_Backend b;

	enesim_surface_lock(s, EINA_TRUE);
	b = enesim_surface_backend_get(s);
	switch (b)
	{
		case ENESIM_BACKEND_SOFTWARE:
		enesim_renderer_sw_draw_area(r, s, area, x, y);
		break;

		case ENESIM_BACKEND_OPENCL:
#if BUILD_OPENCL
		enesim_renderer_opencl_draw(r, s, area, x, y);
#endif
		break;

		case ENESIM_BACKEND_OPENGL:
#if BUILD_OPENGL
		enesim_renderer_opengl_draw(r, s, area, x, y);
#endif
		break;

		default:
		WRN("Backend not supported %d", b);
		break;
	}
	enesim_surface_unlock(s);
}

static void _draw_list_internal(Enesim_Renderer *r, Enesim_Surface *s,
		Eina_Rectangle *area,
		Eina_List *clips, int x, int y)
{
	Enesim_Backend b;
	Eina_Rectangle *clip;
	Eina_List *l;

	enesim_surface_lock(s, EINA_TRUE);
	b = enesim_surface_backend_get(s);
	switch (b)
	{
		case ENESIM_BACKEND_SOFTWARE:
		EINA_LIST_FOREACH(clips, l, clip)
		{
			Eina_Rectangle final;

			final = *clip;
			if (!eina_rectangle_intersection(&final, area))
				continue;
			enesim_renderer_sw_draw_area(r, s, &final, x, y);
		}
		break;

		case ENESIM_BACKEND_OPENGL:
#if BUILD_OPENGL
		EINA_LIST_FOREACH(clips, l, clip)
		{
			Eina_Rectangle final;

			final = *clip;
			if (!eina_rectangle_intersection(&final, area))
				continue;
			enesim_renderer_opengl_draw(r, s, &final, x, y);
		}
#endif
		break;

		default:
		WRN("Backend not supported %d", b);
		break;
	}
	enesim_surface_unlock(s);
}

static inline void _surface_bounds(Enesim_Surface *s, Eina_Rectangle *bounds)
{
	bounds->x = 0;
	bounds->y = 0;
	enesim_surface_size_get(s, &bounds->w, &bounds->h);
}

static void _enesim_renderer_factory_setup(Enesim_Renderer *r)
{
	Enesim_Renderer_Factory *f;
	char renderer_name[PATH_MAX];
	const char *descriptor_name = NULL;

	if (!_factories) return;
	if (r->descriptor.name)
		descriptor_name = r->descriptor.name(r);
	if (!descriptor_name)
		descriptor_name = "unknown";
	f = eina_hash_find(_factories, descriptor_name);
	if (!f)
	{
		f = calloc(1, sizeof(Enesim_Renderer_Factory));
		eina_hash_add(_factories, descriptor_name, f);
	}
	/* assign a new name for it automatically */
	snprintf(renderer_name, PATH_MAX, "%s%d", descriptor_name, f->id++);
	enesim_renderer_name_set(r, renderer_name);
}

static Eina_Bool _enesim_renderer_common_changed(Enesim_Renderer *r)
{
	/* the visibility */
	if (r->current.visibility != r->past.visibility)
	{
		return EINA_TRUE;
	}
	/* the rop */
	if (r->current.rop != r->past.rop)
	{
		return EINA_TRUE;
	}
	/* the color */
	if (r->current.color != r->past.color)
	{
		return EINA_TRUE;
	}
	/* the mask */
	if (r->current.mask && !r->past.mask)
		return EINA_TRUE;
	if (!r->current.mask && r->past.mask)
		return EINA_TRUE;
	if (r->current.mask)
	{
		if (enesim_renderer_has_changed(r->current.mask))
		{
			DBG("The mask renderer %s has changed", r->name);
			return EINA_TRUE;
		}
	}
	/* the origin */
	if (r->current.ox != r->past.ox || r->current.oy != r->past.oy)
	{
		return EINA_TRUE;
	}
	/* the transformation */
	if (r->current.transformation_type != r->past.transformation_type)
	{
		return EINA_TRUE;
	}

	if (!enesim_matrix_is_equal(&r->current.transformation, &r->past.transformation))
	{
		return EINA_TRUE;
	}

	return EINA_FALSE;
}
/*============================================================================*
 *                                 Global                                     *
 *============================================================================*/
void enesim_renderer_init(void)
{
	_factories = eina_hash_string_superfast_new(
			_enesim_renderer_factory_free);
	enesim_renderer_sw_init();
#if BUILD_OPENGL
	enesim_renderer_opengl_init();
#endif
}

void enesim_renderer_shutdown(void)
{
	eina_hash_free(_factories);
	_factories = NULL;
	enesim_renderer_sw_shutdown();
}

/* FIXME export this */
void * enesim_renderer_backend_data_get(Enesim_Renderer *r, Enesim_Backend b)
{
	return r->backend_data[b];
}

void enesim_renderer_backend_data_set(Enesim_Renderer *r, Enesim_Backend b, void *data)
{
	r->backend_data[b] = data;
}
/*============================================================================*
 *                                   API                                      *
 *============================================================================*/
/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI Enesim_Renderer * enesim_renderer_new(Enesim_Renderer_Descriptor
		*descriptor, void *data)
{
	Enesim_Renderer *r;

	if (!descriptor) return NULL;
	if (descriptor->version > ENESIM_RENDERER_API) {
		ERR("API version %d is greater than %d", descriptor->version, ENESIM_RENDERER_API);
		return NULL;
	}

	r = calloc(1, sizeof(Enesim_Renderer));
	/* first check the passed in functions */
	if (!descriptor->is_inside) WRN("No is_inside() function available");
	if (!descriptor->bounds) WRN("No bounding() function available");
	if (!descriptor->flags) WRN("No flags() function available");
	if (!descriptor->sw_setup) WRN("No sw_setup() function available");
	if (!descriptor->sw_cleanup) WRN("No sw_cleanup() function available");
	if (!descriptor->free) WRN("No free() function available");
	r->descriptor = *descriptor;
	r->data = data;
	/* now initialize the renderer common properties */
	EINA_MAGIC_SET(r, ENESIM_MAGIC_RENDERER);
	/* common properties */
	r->current.visibility = r->past.visibility = EINA_TRUE;
	r->current.ox = r->past.ox = 0;
	r->current.oy = r->past.oy = 0;
	r->current.color = r->past.color = ENESIM_COLOR_FULL;
	r->current.rop = r->past.rop = ENESIM_FILL;
	enesim_matrix_identity(&r->current.transformation);
	enesim_matrix_identity(&r->past.transformation);
	r->current.transformation_type = ENESIM_MATRIX_IDENTITY;
	r->past.transformation_type = ENESIM_MATRIX_IDENTITY;
	/* private stuff */
	r->current_flags = 0;
	enesim_rectangle_coords_from(&r->past_bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	eina_rectangle_coords_from(&r->past_destination_bounds, INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
	r->prv_data = eina_hash_string_superfast_new(NULL);
	eina_lock_new(&r->lock);
	/* always set the first reference */
	r = enesim_renderer_ref(r);
	_enesim_renderer_factory_setup(r);

	return r;
}

/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI void * enesim_renderer_data_get(Enesim_Renderer *r)
{
	ENESIM_MAGIC_CHECK_RENDERER(r);

	return r->data;
}

/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI Enesim_Renderer * enesim_renderer_ref(Enesim_Renderer *r)
{
	ENESIM_MAGIC_CHECK_RENDERER(r);
	r->ref++;
	return r;
}

/**
 * To be documented
 * FIXME: To be fixed
 */
EAPI void enesim_renderer_unref(Enesim_Renderer *r)
{
	ENESIM_MAGIC_CHECK_RENDERER(r);
	r->ref--;
	if (!r->ref)
	{
		if (r->descriptor.free)
			r->descriptor.free(r);
		if (r->name)
			free(r->name);
{'fraction_non_alphanumeric': 0.1687497029891175, 'fraction_numerical': 0.0031364349189754314, 'mean_word_length': 4.106527541858772, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 149, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '485032', 'n_tokens_mistral': 7760, 'n_tokens_neox': 7402, 'n_words': 1656}