Learn-to-Compress / src / codecs.cpp
codecs.cpp
Raw
/**
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 * (c) Daniel Lemire, http://lemire.me/en/
 */
#ifndef _MSC_VER
#include <getopt.h>
#else 
#ifndef __GETOPT_H__
 /**
 * DISCLAIMER
 * This file is part of the mingw-w64 runtime package.
 *
 * The mingw-w64 runtime package and its code is distributed in the hope that it
 * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR
 * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to
 * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
 /*
 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Sponsored in part by the Defense Advanced Research Projects
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
 */
 /*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Dieter Baron and Thomas Klausner.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#pragma warning(disable:4996)

#define __GETOPT_H__

 /* All the headers include this file. */
#include <crtdefs.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#define NOMINMAX
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */

#ifdef REPLACE_GETOPT
	int	opterr = 1;		/* if error message should be printed */
	int	optind = 1;		/* index into parent argv vector */
	int	optopt = '?';		/* character checked for validity */
#undef	optreset		/* see getopt.h */
#define	optreset		__mingw_optreset
	int	optreset;		/* reset getopt */
	char    *optarg;		/* argument associated with option */
#endif

							//extern int optind;		/* index of first non-option in argv      */
							//extern int optopt;		/* single option character, as parsed     */
							//extern int opterr;		/* flag to enable built-in diagnostics... */
							//				/* (user may set to zero, to suppress)    */
							//
							//extern char *optarg;		/* pointer to argument of current option  */

#define PRINT_ERROR	((opterr) && (*options != ':'))

#define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
#define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
#define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */

							/* return values */
#define	BADCH		(int)'?'
#define	BADARG		((*options == ':') ? (int)':' : (int)'?')
#define	INORDER 	(int)1

#ifndef __CYGWIN__
#define __progname __argv[0]
#else
	extern char __declspec(dllimport) *__progname;
#endif

#ifdef __CYGWIN__
	static char EMSG[] = "";
#else
#define	EMSG		""
#endif

	static int getopt_internal(int, char * const *, const char *,
		const struct option *, int *, int);
	static int parse_long_options(char * const *, const char *,
		const struct option *, int *, int);
	static int gcd(int, int);
	static void permute_args(int, int, int, char * const *);

	static char *place = EMSG; /* option letter processing */

							   /* XXX: set optreset to 1 rather than these two */
	static int nonopt_start = -1; /* first non option argument (for permute) */
	static int nonopt_end = -1;   /* first option after non options (for permute) */

								  /* Error messages */
	static const char recargchar[] = "option requires an argument -- %c";
	static const char recargstring[] = "option requires an argument -- %s";
	static const char ambig[] = "ambiguous option -- %.*s";
	static const char noarg[] = "option doesn't take an argument -- %.*s";
	static const char illoptchar[] = "unknown option -- %c";
	static const char illoptstring[] = "unknown option -- %s";

	static void
		_vwarnx(const char *fmt, va_list ap)
	{
		(void)fprintf(stderr, "%s: ", __progname);
		if (fmt != NULL)
			(void)vfprintf(stderr, fmt, ap);
		(void)fprintf(stderr, "\n");
	}

	static void
		warnx(const char *fmt, ...)
	{
		va_list ap;
		va_start(ap, fmt);
		_vwarnx(fmt, ap);
		va_end(ap);
	}

	/*
	* Compute the greatest common divisor of a and b.
	*/
	static int
		gcd(int a, int b)
	{
		int c;

		c = a % b;
		while (c != 0) {
			a = b;
			b = c;
			c = a % b;
		}

		return (b);
	}

	/*
	* Exchange the block from nonopt_start to nonopt_end with the block
	* from nonopt_end to opt_end (keeping the same order of arguments
	* in each block).
	*/
	static void
		permute_args(int panonopt_start, int panonopt_end, int opt_end,
			char * const *nargv)
	{
		int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
		char *swap;

		/*
		* compute lengths of blocks and number and size of cycles
		*/
		nnonopts = panonopt_end - panonopt_start;
		nopts = opt_end - panonopt_end;
		ncycle = gcd(nnonopts, nopts);
		cyclelen = (opt_end - panonopt_start) / ncycle;

		for (i = 0; i < ncycle; i++) {
			cstart = panonopt_end + i;
			pos = cstart;
			for (j = 0; j < cyclelen; j++) {
				if (pos >= panonopt_end)
					pos -= nnonopts;
				else
					pos += nopts;
				swap = nargv[pos];
				/* LINTED const cast */
				((char **)nargv)[pos] = nargv[cstart];
				/* LINTED const cast */
				((char **)nargv)[cstart] = swap;
			}
		}
	}

#ifdef REPLACE_GETOPT
	/*
	* getopt --
	*	Parse argc/argv argument vector.
	*
	* [eventually this will replace the BSD getopt]
	*/
	int
		getopt(int nargc, char * const *nargv, const char *options)
	{

		/*
		* We don't pass FLAG_PERMUTE to getopt_internal() since
		* the BSD getopt(3) (unlike GNU) has never done this.
		*
		* Furthermore, since many privileged programs call getopt()
		* before dropping privileges it makes sense to keep things
		* as simple (and bug-free) as possible.
		*/
		return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
	}
#endif /* REPLACE_GETOPT */

	//extern int getopt(int nargc, char * const *nargv, const char *options);

#ifdef _BSD_SOURCE
	/*
	* BSD adds the non-standard `optreset' feature, for reinitialisation
	* of `getopt' parsing.  We support this feature, for applications which
	* proclaim their BSD heritage, before including this header; however,
	* to maintain portability, developers are advised to avoid it.
	*/
# define optreset  __mingw_optreset
	extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header.  However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner.  Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#endif /* !defined(__GETOPT_H__) */

#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__

#ifdef __cplusplus
extern "C" {
#endif

	struct option		/* specification for a long form option...	*/
	{
		const char *name;		/* option name, without leading hyphens */
		int         has_arg;		/* does it take an argument?		*/
		int        *flag;		/* where to save its status, or NULL	*/
		int         val;		/* its associated status value		*/
	};

	enum    		/* permitted values for its `has_arg' field...	*/
	{
		no_argument = 0,      	/* option never takes an argument	*/
		required_argument,		/* option always requires an argument	*/
		optional_argument		/* option may take an argument		*/
	};

	/*
	* parse_long_options --
	*	Parse long options in argc/argv argument vector.
	* Returns -1 if short_too is set and the option does not match long_options.
	*/
	static int
		parse_long_options(char * const *nargv, const char *options,
			const struct option *long_options, int *idx, int short_too)
	{
		char *current_argv, *has_equal;
		size_t current_argv_len;
		int i, ambiguous, match;

#define IDENTICAL_INTERPRETATION(_x, _y)                                \
	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
	 long_options[(_x)].val == long_options[(_y)].val)

		current_argv = place;
		match = -1;
		ambiguous = 0;

		optind++;

		if ((has_equal = strchr(current_argv, '=')) != NULL) {
			/* argument found (--option=arg) */
			current_argv_len = has_equal - current_argv;
			has_equal++;
		}
		else
			current_argv_len = strlen(current_argv);

		for (i = 0; long_options[i].name; i++) {
			/* find matching long option */
			if (strncmp(current_argv, long_options[i].name,
				current_argv_len))
				continue;

			if (strlen(long_options[i].name) == current_argv_len) {
				/* exact match */
				match = i;
				ambiguous = 0;
				break;
			}
			/*
			* If this is a known short option, don't allow
			* a partial match of a single character.
			*/
			if (short_too && current_argv_len == 1)
				continue;

			if (match == -1)	/* partial match */
				match = i;
			else if (!IDENTICAL_INTERPRETATION(i, match))
				ambiguous = 1;
		}
		if (ambiguous) {
			/* ambiguous abbreviation */
			if (PRINT_ERROR)
				warnx(ambig, (int)current_argv_len,
					current_argv);
			optopt = 0;
			return (BADCH);
		}
		if (match != -1) {		/* option found */
			if (long_options[match].has_arg == no_argument
				&& has_equal) {
				if (PRINT_ERROR)
					warnx(noarg, (int)current_argv_len,
						current_argv);
				/*
				* XXX: GNU sets optopt to val regardless of flag
				*/
				if (long_options[match].flag == NULL)
					optopt = long_options[match].val;
				else
					optopt = 0;
				return (BADARG);
			}
			if (long_options[match].has_arg == required_argument ||
				long_options[match].has_arg == optional_argument) {
				if (has_equal)
					optarg = has_equal;
				else if (long_options[match].has_arg ==
					required_argument) {
					/*
					* optional argument doesn't use next nargv
					*/
					optarg = nargv[optind++];
				}
			}
			if ((long_options[match].has_arg == required_argument)
				&& (optarg == NULL)) {
				/*
				* Missing argument; leading ':' indicates no error
				* should be generated.
				*/
				if (PRINT_ERROR)
					warnx(recargstring,
						current_argv);
				/*
				* XXX: GNU sets optopt to val regardless of flag
				*/
				if (long_options[match].flag == NULL)
					optopt = long_options[match].val;
				else
					optopt = 0;
				--optind;
				return (BADARG);
			}
		}
		else {			/* unknown option */
			if (short_too) {
				--optind;
				return (-1);
			}
			if (PRINT_ERROR)
				warnx(illoptstring, current_argv);
			optopt = 0;
			return (BADCH);
		}
		if (idx)
			*idx = match;
		if (long_options[match].flag) {
			*long_options[match].flag = long_options[match].val;
			return (0);
		}
		else
			return (long_options[match].val);
#undef IDENTICAL_INTERPRETATION
	}

	/*
	* getopt_internal --
	*	Parse argc/argv argument vector.  Called by user level routines.
	*/
	static int
		getopt_internal(int nargc, char * const *nargv, const char *options,
			const struct option *long_options, int *idx, int flags)
	{
		char *oli;				/* option letter list index */
		int optchar, short_too;
		static int posixly_correct = -1;

		if (options == NULL)
			return (-1);

		/*
		* XXX Some GNU programs (like cvs) set optind to 0 instead of
		* XXX using optreset.  Work around this braindamage.
		*/
		if (optind == 0)
			optind = optreset = 1;

		/*
		* Disable GNU extensions if POSIXLY_CORRECT is set or options
		* string begins with a '+'.
		*
		* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
		*                 optreset != 0 for GNU compatibility.
		*/
		if (posixly_correct == -1 || optreset != 0)
			posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
		if (*options == '-')
			flags |= FLAG_ALLARGS;
		else if (posixly_correct || *options == '+')
			flags &= ~FLAG_PERMUTE;
		if (*options == '+' || *options == '-')
			options++;

		optarg = NULL;
		if (optreset)
			nonopt_start = nonopt_end = -1;
	start:
		if (optreset || !*place) {		/* update scanning pointer */
			optreset = 0;
			if (optind >= nargc) {          /* end of argument vector */
				place = EMSG;
				if (nonopt_end != -1) {
					/* do permutation, if we have to */
					permute_args(nonopt_start, nonopt_end,
						optind, nargv);
					optind -= nonopt_end - nonopt_start;
				}
				else if (nonopt_start != -1) {
					/*
					* If we skipped non-options, set optind
					* to the first of them.
					*/
					optind = nonopt_start;
				}
				nonopt_start = nonopt_end = -1;
				return (-1);
			}
			if (*(place = nargv[optind]) != '-' ||
				(place[1] == '\0' && strchr(options, '-') == NULL)) {
				place = EMSG;		/* found non-option */
				if (flags & FLAG_ALLARGS) {
					/*
					* GNU extension:
					* return non-option as argument to option 1
					*/
					optarg = nargv[optind++];
					return (INORDER);
				}
				if (!(flags & FLAG_PERMUTE)) {
					/*
					* If no permutation wanted, stop parsing
					* at first non-option.
					*/
					return (-1);
				}
				/* do permutation */
				if (nonopt_start == -1)
					nonopt_start = optind;
				else if (nonopt_end != -1) {
					permute_args(nonopt_start, nonopt_end,
						optind, nargv);
					nonopt_start = optind -
						(nonopt_end - nonopt_start);
					nonopt_end = -1;
				}
				optind++;
				/* process next argument */
				goto start;
			}
			if (nonopt_start != -1 && nonopt_end == -1)
				nonopt_end = optind;

			/*
			* If we have "-" do nothing, if "--" we are done.
			*/
			if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
				optind++;
				place = EMSG;
				/*
				* We found an option (--), so if we skipped
				* non-options, we have to permute.
				*/
				if (nonopt_end != -1) {
					permute_args(nonopt_start, nonopt_end,
						optind, nargv);
					optind -= nonopt_end - nonopt_start;
				}
				nonopt_start = nonopt_end = -1;
				return (-1);
			}
		}

		/*
		* Check long options if:
		*  1) we were passed some
		*  2) the arg is not just "-"
		*  3) either the arg starts with -- we are getopt_long_only()
		*/
		if (long_options != NULL && place != nargv[optind] &&
			(*place == '-' || (flags & FLAG_LONGONLY))) {
			short_too = 0;
			if (*place == '-')
				place++;		/* --foo long option */
			else if (*place != ':' && strchr(options, *place) != NULL)
				short_too = 1;		/* could be short option too */

			optchar = parse_long_options(nargv, options, long_options,
				idx, short_too);
			if (optchar != -1) {
				place = EMSG;
				return (optchar);
			}
		}

		if ((optchar = (int)*place++) == (int)':' ||
			(optchar == (int)'-' && *place != '\0') ||
			(oli = (char*)strchr(options, optchar)) == NULL) {
			/*
			* If the user specified "-" and  '-' isn't listed in
			* options, return -1 (non-option) as per POSIX.
			* Otherwise, it is an unknown option character (or ':').
			*/
			if (optchar == (int)'-' && *place == '\0')
				return (-1);
			if (!*place)
				++optind;
			if (PRINT_ERROR)
				warnx(illoptchar, optchar);
			optopt = optchar;
			return (BADCH);
		}
		if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
			/* -W long-option */
			if (*place)			/* no space */
				/* NOTHING */;
			else if (++optind >= nargc) {	/* no arg */
				place = EMSG;
				if (PRINT_ERROR)
					warnx(recargchar, optchar);
				optopt = optchar;
				return (BADARG);
			}
			else				/* white space */
				place = nargv[optind];
			optchar = parse_long_options(nargv, options, long_options,
				idx, 0);
			place = EMSG;
			return (optchar);
		}
		if (*++oli != ':') {			/* doesn't take argument */
			if (!*place)
				++optind;
		}
		else {				/* takes (optional) argument */
			optarg = NULL;
			if (*place)			/* no white space */
				optarg = place;
			else if (oli[1] != ':') {	/* arg not optional */
				if (++optind >= nargc) {	/* no arg */
					place = EMSG;
					if (PRINT_ERROR)
						warnx(recargchar, optchar);
					optopt = optchar;
					return (BADARG);
				}
				else
					optarg = nargv[optind];
			}
			place = EMSG;
			++optind;
		}
		/* dump back option letter */
		return (optchar);
	}

	/*
	* getopt_long --
	*	Parse argc/argv argument vector.
	*/
	int
		getopt_long(int nargc, char * const *nargv, const char *options,
			const struct option *long_options, int *idx)
	{

		return (getopt_internal(nargc, nargv, options, long_options, idx,
			FLAG_PERMUTE));
	}

	/*
	* getopt_long_only --
	*	Parse argc/argv argument vector.
	*/
	int
		getopt_long_only(int nargc, char * const *nargv, const char *options,
			const struct option *long_options, int *idx)
	{

		return (getopt_internal(nargc, nargv, options, long_options, idx,
			FLAG_PERMUTE | FLAG_LONGONLY));
	}

	//extern int getopt_long(int nargc, char * const *nargv, const char *options,
	//    const struct option *long_options, int *idx);
	//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
	//    const struct option *long_options, int *idx);
	/*
	* Previous MinGW implementation had...
	*/
#ifndef HAVE_DECL_GETOPT
	/*
	* ...for the long form API only; keep this for compatibility.
	*/
# define HAVE_DECL_GETOPT	1
#endif

#ifdef __cplusplus
}
#endif

#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
#endif

#include <string.h>
#include <time.h>
#include <cstdlib>
#include <ctype.h>
#include <memory>
#include <iomanip>
#include "../headers/codecfactory.h"
#include "../headers/ztimer.h"

#include "../headers/entropy.h"
#include "../headers/memutil.h"


using namespace std;
using namespace FastPForLib;

static struct option long_options[] = {
    {"uniformsparseclassic", no_argument, 0, 0},
    {"displayhistogram", no_argument, 0, 'H'},
    {"uniformdenseclassic", no_argument, 0, 0},
    {"clustersparseclassic", no_argument, 0, 0},
    {"clusterdenseclassic", no_argument, 0, 0},
    {"uniformsparse", no_argument, 0, 0},
    {"uniformdense", no_argument, 0, 0},
    {"clustersparse", no_argument, 0, 0},
    {"clusterdense", no_argument, 0, 0},
    {"zipfian1", no_argument, 0, 0},
    {"zipfian2", no_argument, 0, 0},
    {"vclusterdynamic", no_argument, 0, 0},
    {"crazyclusterdynamic", no_argument, 0, 0},
    {"clusterdynamicsmall", no_argument, 0, 0},
    {"uniformdynamicsmall", no_argument, 0, 0},
    {"clusterdynamic", no_argument, 0, 0},
    {"uniformdynamic", no_argument, 0, 0},
    {"clusterdynamicpredelta", no_argument, 0, 0},
    {"uniformdynamicpredelta", no_argument, 0, 0},
    {"sillyuniformdynamic", no_argument, 0, 0},
    {"codecs", required_argument, 0, 'c'},
    {"splitlongarrays", no_argument, 0, 'S'},
    {"short", no_argument, 0, 's'},
    {0, 0, 0, 0}};

void message() {
  int c = 0;
  cout << "You must select one of these options:" << endl;
  while (long_options[c].name != 0) {
    if ((strcmp(long_options[c].name, "codecs") == 0) ||
        ((strcmp(long_options[c].name, "short") == 0)))
      ++c;
    else
      cout << "--" << long_options[c++].name << endl;
  }
  cout << "the --codecs flag takes as an argument"
          " a comma-separated list of schemes chosen among those:"
       << endl;
  vector<string> all = CODECFactory::allNames();
  for (auto i = all.begin(); i != all.end(); ++i) {
    cout << *i;
    if (i + 1 == all.end())
      cout << endl;
    else
      cout << ",";
  }
  cout << "(or give NONE instead of a list)" << endl;
  cout << "The --displayhistogram flag must appear before the other flags."
       << endl;
  cout << "Note that the --codecs flag must appear before the other flags."
       << endl;
  cout << "You can get a more concise output by using the --short flag."
       << endl;
}

int main(int argc, char **argv) {
  srand(10); // time(NULL));
  bool fulldisplay = true;
  bool displayhistogram = false;
  bool computeentropy = false;

  bool splitlongarrays = true;
  vector<shared_ptr<IntegerCODEC>> tmp =
      CODECFactory::allSchemes(); // the default
  vector<algostats> myalgos;
  for (auto &i : tmp) {
    myalgos.push_back(algostats(i));
    myalgos.push_back(algostats(i, true)); // by default?
  }
  int c;
  while (1) {
    int option_index = 0;
    c = getopt_long(argc, argv, "Sfec:", long_options, &option_index);
    if (c == -1)
      break;
    switch (c) {
    case 'S':
      cout << "#\n# disabling partition of big arrays. Performance may "
              "suffer.#\n"
           << endl;
      splitlongarrays = false;
      break;
    case 'c': {
      myalgos.clear();
      string codecsstr(optarg);
      if (codecsstr.compare("NONE") != 0) {
        vector<string> codecslst = split(codecsstr, ",:;");
        for (auto i = codecslst.begin(); i != codecslst.end(); ++i) {
          cout << "# pretty name = " << *i << endl;
          if (i->at(0) == '@') { // SIMD
            myalgos.push_back(algostats(
                CODECFactory::getFromName(i->substr(1, i->size() - 1)), true));
          } else {
            myalgos.push_back(algostats(CODECFactory::getFromName(*i)));
          }
          cout << "# added '" << myalgos.back().name() << "'" << endl;
        }
      }
    } break;
    case 'e':
      computeentropy = true;
      break;
    case 'H':
      displayhistogram = true;
      break;
    case 's':
      fulldisplay = false;
      break;
    case 'f':
      fulldisplay = true;
      break;
    case 0: {
      if (optind < argc) {
        cout << "There are some trailing flags...?" << endl;
        message();
        return 0;
      }
      const char *parameter = long_options[option_index].name;
      cout << "# found " << parameter << endl;
      if (strcmp(parameter, "zipfian1") == 0) {
        const uint32_t N = 4194304 * 16;
        vector<vector<uint32_t, cacheallocator>> datas;
        cout << "# zipfian 1 data generation..." << endl;
        for (uint32_t k = 0; k < (1U << 1); ++k)
          datas.push_back(generateZipfianArray32(N, 1.0, 1U << 20));
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(false, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "zipfian2") == 0) {
        const uint32_t N = 4194304 * 16;
        vector<vector<uint32_t, cacheallocator>> datas;
        for (uint32_t k = 0; k < (1U << 1); ++k)
          cout << "# zipfian 2 data generation..." << endl;
        datas.push_back(generateZipfianArray32(N, 2.0, 1U << 20));
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(false, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformdenseclassic") == 0) {
        cout << "# dense uniform data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        UniformDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 5); ++k)
          datas.push_back(clu.generateUniform((1U << 18), 1U << 27));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformsparseclassic") == 0) {
        cout << "# sparse uniform data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        UniformDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 14);
             ++k) // by original paper should be 1U<<19
          datas.push_back(clu.generateUniform((1U << 9), 1U << 27));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clusterdenseclassic") == 0) {
        cout << "# dense cluster data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        ClusteredDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 5);
             ++k) // by original paper should be 1U<<10
          datas.push_back(clu.generateClustered((1U << 18), 1U << 27));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clustersparseclassic") == 0) {
        cout << "# sparse cluster data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        ClusteredDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 14);
             ++k) // by original paper should be 1U<<19
          datas.push_back(clu.generateClustered((1U << 9), 1U << 27));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformdense") == 0) {
        cout << "# dense uniform data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        UniformDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 3);
             ++k) // by original paper should be 1U<<10
          datas.push_back(clu.generateUniform((1U << 22), 1U << 29));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformsparse") == 0) {
        cout << "# sparse uniform data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        UniformDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 13); ++k)
          datas.push_back(clu.generateUniform((1U << 12), 1U << 29));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clusterdense") == 0) {
        cout << "# dense cluster data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        ClusteredDataGenerator clu;
        for (uint32_t k = 0; k < 1; ++k)
          datas.push_back(clu.generateClustered((1U << 23), 1U << 26));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clustersparse") == 0) {
        cout << "# sparse cluster data generation..." << endl;
        vector<vector<uint32_t, cacheallocator>> datas;
        ClusteredDataGenerator clu;
        for (uint32_t k = 0; k < (1U << 13); ++k)
          datas.push_back(clu.generateClustered((1U << 12), 1U << 26));
        cout << "# generated " << datas.size() << " arrays" << endl;
        if (splitlongarrays)
          splitLongArrays(datas);
        processparameters pp(true, fulldisplay, displayhistogram,
                             computeentropy, false);
        Delta::process(myalgos, datas, pp);
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clusterdynamic") == 0) {
        cout << "# dynamic clustered data generation..." << endl;
        ClusteredDataGenerator clu;
        for (uint32_t K = 15; K <= 25; K += 5) {
          vector<vector<uint32_t, cacheallocator>> datas;
          for (uint32_t k = 0; k < (1U << (25 - K)); ++k)
            datas.push_back(clu.generateClustered((1U << K), 1U << 29));
          cout << "# generated " << datas.size() << " arrays" << endl;
          cout << "# their size is  " << (1U << K) << endl;
          const uint32_t p = 29 - K;
          ostringstream convert;
          convert << p;
          if (splitlongarrays)
            splitLongArrays(datas);
          processparameters pp(true, fulldisplay, displayhistogram,
                               computeentropy, false);
          Delta::process(myalgos, datas, pp, convert.str());
        }
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformdynamic") == 0) {
        cout << "# sparse uniform data generation..." << endl;
        UniformDataGenerator clu;
        for (uint32_t K = 15; K <= 25; K += 5) {
          vector<vector<uint32_t, cacheallocator>> datas;
          for (uint32_t k = 0; k < (1U << (25 - K)); ++k)
            datas.push_back(clu.generateUniform((1U << K), 1U << 29));
          cout << "# generated " << datas.size() << " arrays" << endl;
          cout << "# their size is  " << (1U << K) << endl;
          const uint32_t p = 29 - K;
          ostringstream convert;
          convert << p;
          if (splitlongarrays)
            splitLongArrays(datas);
          processparameters pp(true, fulldisplay, displayhistogram,
                               computeentropy, false);
          Delta::process(myalgos, datas, pp, convert.str());
        }
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clusterdynamicsmall") == 0) {
        cout << "# dynamic clustered data generation..." << endl;
        ClusteredDataGenerator clu;
        for (uint32_t K = 15; K <= 20; K += 5) {
          vector<vector<uint32_t, cacheallocator>> datas;
          for (size_t k = 0; k < static_cast<size_t>(1U << (20 - K)); ++k)
            datas.push_back(clu.generateClustered((1U << K), 1U << 29));
          cout << "# generated " << datas.size() << " arrays" << endl;
          cout << "# their size is  " << (1U << K) << endl;
          const uint32_t p = 29 - K;
          ostringstream convert;
          convert << p;
          if (splitlongarrays)
            splitLongArrays(datas);
          processparameters pp(true, fulldisplay, displayhistogram,
                               computeentropy, false);
          Delta::process(myalgos, datas, pp, convert.str());
        }
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformdynamicsmall") == 0) {
        cout << "# sparse uniform data generation..." << endl;
        UniformDataGenerator clu;
        for (uint32_t K = 15; K <= 20; K += 5) {
          vector<vector<uint32_t, cacheallocator>> datas;
          for (size_t k = 0; k < static_cast<size_t>(1U << (20 - K)); ++k)
            datas.push_back(clu.generateUniform((1U << K), 1U << 29));
          cout << "# generated " << datas.size() << " arrays" << endl;
          cout << "# their size is  " << (1U << K) << endl;
          const uint32_t p = 29 - K;
          ostringstream convert;
          convert << p;
          if (splitlongarrays)
            splitLongArrays(datas);
          processparameters pp(true, fulldisplay, displayhistogram,
                               computeentropy, false);
          Delta::process(myalgos, datas, pp, convert.str());
        }
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "clusterdynamicpredelta") == 0) {
        cout << "# dynamic clustered data generation..." << endl;
        ClusteredDataGenerator clu;
        for (uint32_t K = 15; K <= 25; K += 5) {
          vector<vector<uint32_t, cacheallocator>> datas;
          for (size_t k = 0; k < static_cast<size_t>(1U << (25 - K)); ++k)
            datas.push_back(
                diffs(clu.generateClustered((1U << K), 1U << 29), false));
          cout << "# generated " << datas.size()
               << " arrays and applied delta coding" << endl;
          cout << "# their size is  " << (1U << K) << endl;
          const uint32_t p = 29 - K;
          ostringstream convert;
          convert << p;
          if (splitlongarrays)
            splitLongArrays(datas);
          processparameters pp(false, fulldisplay, displayhistogram,
                               computeentropy, false);
          Delta::process(myalgos, datas, pp, convert.str());
        }
        summarize(myalgos, "#");
        return 0;
      } else if (strcmp(parameter, "uniformdynamicpredelta") == 0) {
        cout << "# sparse uniform data generation..." << endl;
        UniformDataGenerator clu;
        for (uint32_t K = 15; K <= 25; K += 5) {
          vector<vector<uint32_t, cacheallocator>> datas;
          for (size_t k = 0; k < static_cast<size_t>(1U << (25 - K)); ++k)
            datas.push_back(
                diffs(clu.generateUniform((1U << K), 1U << 29), false));
          cout << "# generated " << datas.size()
               << " arrays and applied delta coding" << endl;
          cout << "# their size is  " << (1U << K) << endl;
          const uint32_t p = 29 - K;
          ostringstream convert;
          convert << p;
          if (splitlongarrays)
            splitLongArrays(datas);
          processparameters pp(false, fulldisplay, displayhistogram,
                               computeentropy, false);
          Delta::process(myalgos, datas, pp, convert.str());
        }
        summarize(myalgos, "#");
        return 0;
      } else {
        cerr << "Support for " << parameter << " was not found." << endl;
      }
      break;
    }
    default:
      /* You won't actually get here. */
      break;
    }
  }
  message();
  return 0;
}