<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or 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.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

#define XC7_WIRE_DELAY "300" // Number with which ABC will map a 6-input gate
                             // to one LUT6 (instead of a LUT5 + LUT2)

struct SynthXilinxPass : public ScriptPass
{
	SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }

	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_xilinx [options]\n");
		log("\n");
		log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n");
		log("partly selected designs. At the moment this command creates netlists that are\n");
		log("compatible with 7-Series Xilinx devices.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module\n");
		log("\n");
		log("    -arch {xcup|xcu|xc7|xc6s}\n");
		log("        run synthesis for the specified Xilinx architecture\n");
		log("        default: xc7\n");
		log("\n");
		log("    -edif <file>\n");
		log("        write the design to the specified edif file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -blif <file>\n");
		log("        write the design to the specified BLIF file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -vpr\n");
		log("        generate an output netlist (and BLIF file) suitable for VPR\n");
		log("        (this feature is experimental and incomplete)\n");
		log("\n");
		log("    -nocarry\n");
		log("        disable inference of carry chains\n");
		log("\n");
		log("    -nobram\n");
		log("        disable inference of block rams\n");
		log("\n");
		log("    -nodram\n");
		log("        disable inference of distributed rams\n");
		log("\n");
		log("    -nosrl\n");
		log("        disable inference of shift registers\n");
		log("\n");
		log("    -nocarry\n");
		log("        do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
		log("\n");
		log("    -nowidelut\n");
		log("        do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -flatten\n");
		log("        flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with -dff option\n");
		log("\n");
		log("    -abc9\n");
		log("        use new ABC9 flow (EXPERIMENTAL)\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	std::string top_opt, edif_file, blif_file, abc, arch;
	bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9;

	void clear_flags() YS_OVERRIDE
	{
		top_opt = "-auto-top";
		edif_file.clear();
		blif_file.clear();
		arch = "xc7";
		flatten = false;
		retime = false;
		vpr = false;
		nocarry = false;
		nobram = false;
		nodram = false;
		nosrl = false;
		nocarry = false;
		nowidelut = false;
		abc9 = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-arch" && argidx+1 < args.size()) {
				arch = args[++argidx];
				continue;
			}
			if (args[argidx] == "-edif" && argidx+1 < args.size()) {
				edif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-blif" && argidx+1 < args.size()) {
				blif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			if (args[argidx] == "-flatten") {
				flatten = true;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			if (args[argidx] == "-nocarry") {
				nocarry = true;
				continue;
			}
			if (args[argidx] == "-nowidelut") {
				nowidelut = true;
				continue;
			}
			if (args[argidx] == "-vpr") {
				vpr = true;
				continue;
			}
			if (args[argidx] == "-nocarry") {
				nocarry = true;
				continue;
			}
			if (args[argidx] == "-nobram") {
				nobram = true;
				continue;
			}
			if (args[argidx] == "-nodram") {
				nodram = true;
				continue;
			}
			if (args[argidx] == "-nosrl") {
				nosrl = true;
				continue;
			}
			if (args[argidx] == "-abc9") {
				abc9 = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
			log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");

		log_header(design, "Executing SYNTH_XILINX pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() YS_OVERRIDE
	{
		if (check_label("begin")) {
			if (vpr)
				run("read_verilog -lib -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
			else
				run("read_verilog -lib -D _ABC +/xilinx/cells_sim.v");

			run("read_verilog -lib +/xilinx/cells_xtra.v");

			if (!nobram || help_mode)
				run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')");

			run(stringf("hierarchy -check %s", top_opt.c_str()));
		}

		if (check_label("flatten", "(with '-flatten' only)")) {
			if (flatten || help_mode) {
				run("proc");
				run("flatten");
			}
		}

		if (check_label("coarse")) {
			run("synth -run coarse");

			// shregmap -tech xilinx can cope with $shiftx and $mux
			//   cells for identifying variable-length shift registers,
			//   so attempt to convert $pmux-es to the former
			if (!nosrl || help_mode)
				run("pmux2shiftx", "(skip if '-nosrl')");

			// Run a number of peephole optimisations, including one
			//   that optimises $mul cells driving $shiftx's B input
			//   and that aids wide mux analysis
			run("peepopt");
		}

		if (check_label("bram", "(skip if '-nobram')")) {
			if (!nobram || help_mode) {
				run("memory_bram -rules +/xilinx/brams.txt");
				run("techmap -map +/xilinx/brams_map.v");
			}
		}

		if (check_label("dram", "(skip if '-nodram')")) {
			if (!nodram || help_mode) {
				run("memory_bram -rules +/xilinx/drams.txt");
				run("techmap -map +/xilinx/drams_map.v");
			}
		}

		if (check_label("fine")) {
			run("opt -fast -full");
			run("memory_map");
			run("dffsr2dff");
			run("dff2dffe");
			run("opt -full");

			if (!nosrl || help_mode) {
				// shregmap operates on bit-level flops, not word-level,
				//   so break those down here
				run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
				// shregmap with '-tech xilinx' infers variable length shift regs
				run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
			}

			std::string techmap_files = " -map +/techmap.v";
			if (help_mode)
				techmap_files += " [-map +/xilinx/arith_map.v]";
			else if (!nocarry) {
				techmap_files += " -map +/xilinx/arith_map.v";
				if (vpr)
					techmap_files += " -D _EXPLICIT_CARRY";
				else if (abc9)
					techmap_files += " -D _CLB_CARRY";
			}
			run("techmap " + techmap_files);
			run("opt -fast");
		}

		if (check_label("map_cells")) {
			run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
			run("clean");
		}

		if (check_label("map_luts")) {
			run("opt_expr -mux_undef");
			if (help_mode)
				run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(skip if 'nowidelut', only for '-retime')");
			else if (abc9) {
				if (nowidelut)
					run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : ""));
				else
					run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : ""));
			}
			else {
				if (nowidelut)
					run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
				else
					run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
			}
			run("clean");

			// This shregmap call infers fixed length shift registers after abc
			//   has performed any necessary retiming
			if (!nosrl || help_mode)
				run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
			run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
			run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
			run("clean");
		}

		if (check_label("check")) {
			run("hierarchy -check");
			run("stat -tech xilinx");
			run("check -noinit");
		}

		if (check_label("edif")) {
			if (!edif_file.empty() || help_mode)
				run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
		}

		if (check_label("blif")) {
			if (!blif_file.empty() || help_mode)
				run(stringf("write_blif %s", edif_file.c_str()));
		}
	}
} SynthXilinxPass;

PRIVATE_NAMESPACE_END
<commit_msg>Remove unused var<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or 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.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

#define XC7_WIRE_DELAY "300" // Number with which ABC will map a 6-input gate
                             // to one LUT6 (instead of a LUT5 + LUT2)

struct SynthXilinxPass : public ScriptPass
{
	SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }

	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_xilinx [options]\n");
		log("\n");
		log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n");
		log("partly selected designs. At the moment this command creates netlists that are\n");
		log("compatible with 7-Series Xilinx devices.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module\n");
		log("\n");
		log("    -arch {xcup|xcu|xc7|xc6s}\n");
		log("        run synthesis for the specified Xilinx architecture\n");
		log("        default: xc7\n");
		log("\n");
		log("    -edif <file>\n");
		log("        write the design to the specified edif file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -blif <file>\n");
		log("        write the design to the specified BLIF file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -vpr\n");
		log("        generate an output netlist (and BLIF file) suitable for VPR\n");
		log("        (this feature is experimental and incomplete)\n");
		log("\n");
		log("    -nocarry\n");
		log("        disable inference of carry chains\n");
		log("\n");
		log("    -nobram\n");
		log("        disable inference of block rams\n");
		log("\n");
		log("    -nodram\n");
		log("        disable inference of distributed rams\n");
		log("\n");
		log("    -nosrl\n");
		log("        disable inference of shift registers\n");
		log("\n");
		log("    -nocarry\n");
		log("        do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
		log("\n");
		log("    -nowidelut\n");
		log("        do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -flatten\n");
		log("        flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with -dff option\n");
		log("\n");
		log("    -abc9\n");
		log("        use new ABC9 flow (EXPERIMENTAL)\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	std::string top_opt, edif_file, blif_file, arch;
	bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9;

	void clear_flags() YS_OVERRIDE
	{
		top_opt = "-auto-top";
		edif_file.clear();
		blif_file.clear();
		arch = "xc7";
		flatten = false;
		retime = false;
		vpr = false;
		nocarry = false;
		nobram = false;
		nodram = false;
		nosrl = false;
		nocarry = false;
		nowidelut = false;
		abc9 = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-arch" && argidx+1 < args.size()) {
				arch = args[++argidx];
				continue;
			}
			if (args[argidx] == "-edif" && argidx+1 < args.size()) {
				edif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-blif" && argidx+1 < args.size()) {
				blif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			if (args[argidx] == "-flatten") {
				flatten = true;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			if (args[argidx] == "-nocarry") {
				nocarry = true;
				continue;
			}
			if (args[argidx] == "-nowidelut") {
				nowidelut = true;
				continue;
			}
			if (args[argidx] == "-vpr") {
				vpr = true;
				continue;
			}
			if (args[argidx] == "-nocarry") {
				nocarry = true;
				continue;
			}
			if (args[argidx] == "-nobram") {
				nobram = true;
				continue;
			}
			if (args[argidx] == "-nodram") {
				nodram = true;
				continue;
			}
			if (args[argidx] == "-nosrl") {
				nosrl = true;
				continue;
			}
			if (args[argidx] == "-abc9") {
				abc9 = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
			log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");

		log_header(design, "Executing SYNTH_XILINX pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() YS_OVERRIDE
	{
		if (check_label("begin")) {
			if (vpr)
				run("read_verilog -lib -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
			else
				run("read_verilog -lib -D _ABC +/xilinx/cells_sim.v");

			run("read_verilog -lib +/xilinx/cells_xtra.v");

			if (!nobram || help_mode)
				run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')");

			run(stringf("hierarchy -check %s", top_opt.c_str()));
		}

		if (check_label("flatten", "(with '-flatten' only)")) {
			if (flatten || help_mode) {
				run("proc");
				run("flatten");
			}
		}

		if (check_label("coarse")) {
			run("synth -run coarse");

			// shregmap -tech xilinx can cope with $shiftx and $mux
			//   cells for identifying variable-length shift registers,
			//   so attempt to convert $pmux-es to the former
			if (!nosrl || help_mode)
				run("pmux2shiftx", "(skip if '-nosrl')");

			// Run a number of peephole optimisations, including one
			//   that optimises $mul cells driving $shiftx's B input
			//   and that aids wide mux analysis
			run("peepopt");
		}

		if (check_label("bram", "(skip if '-nobram')")) {
			if (!nobram || help_mode) {
				run("memory_bram -rules +/xilinx/brams.txt");
				run("techmap -map +/xilinx/brams_map.v");
			}
		}

		if (check_label("dram", "(skip if '-nodram')")) {
			if (!nodram || help_mode) {
				run("memory_bram -rules +/xilinx/drams.txt");
				run("techmap -map +/xilinx/drams_map.v");
			}
		}

		if (check_label("fine")) {
			run("opt -fast -full");
			run("memory_map");
			run("dffsr2dff");
			run("dff2dffe");
			run("opt -full");

			if (!nosrl || help_mode) {
				// shregmap operates on bit-level flops, not word-level,
				//   so break those down here
				run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
				// shregmap with '-tech xilinx' infers variable length shift regs
				run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
			}

			std::string techmap_files = " -map +/techmap.v";
			if (help_mode)
				techmap_files += " [-map +/xilinx/arith_map.v]";
			else if (!nocarry) {
				techmap_files += " -map +/xilinx/arith_map.v";
				if (vpr)
					techmap_files += " -D _EXPLICIT_CARRY";
				else if (abc9)
					techmap_files += " -D _CLB_CARRY";
			}
			run("techmap " + techmap_files);
			run("opt -fast");
		}

		if (check_label("map_cells")) {
			run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
			run("clean");
		}

		if (check_label("map_luts")) {
			run("opt_expr -mux_undef");
			if (help_mode)
				run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(skip if 'nowidelut', only for '-retime')");
			else if (abc9) {
				if (nowidelut)
					run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : ""));
				else
					run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::string(XC7_WIRE_DELAY) + string(retime ? " -dff" : ""));
			}
			else {
				if (nowidelut)
					run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
				else
					run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
			}
			run("clean");

			// This shregmap call infers fixed length shift registers after abc
			//   has performed any necessary retiming
			if (!nosrl || help_mode)
				run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
			run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
			run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
			run("clean");
		}

		if (check_label("check")) {
			run("hierarchy -check");
			run("stat -tech xilinx");
			run("check -noinit");
		}

		if (check_label("edif")) {
			if (!edif_file.empty() || help_mode)
				run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
		}

		if (check_label("blif")) {
			if (!blif_file.empty() || help_mode)
				run(stringf("write_blif %s", edif_file.c_str()));
		}
	}
} SynthXilinxPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/* Copyright (c) 2012, Julian Straub <jstraub@csail.mit.edu>
 * Licensed under the MIT license. See LICENSE.txt or
 * http://www.opensource.org/licenses/mit-license.php */

#pragma once

#include "baseMeasure.hpp"
#include "probabilityHelpers.hpp"

#include <stddef.h>
#include <stdint.h>
#include <typeinfo>

#include <armadillo>

using namespace std;
using namespace arma;

template <class U>
class HDP // : public DP<U>
{
  public:
    HDP(const BaseMeasure<U>& base, double alpha, double omega)
      : mH(base), mAlpha(alpha), mOmega(omega)
    { };

    ~HDP()
    {	};

    /*
     * interface mainly for python
     * @return the index of the added x_i in the set of all documents
     */
    uint32_t addDoc(const Mat<U>& x_i)
    {
      mX.push_back(x_i);
      return mX.size()-1;
    };

    // interface mainly for python
    uint32_t addHeldOut(const Mat<U>& x_i)
    {
      //cout<<"added heldout doc with "<<x_i.size()<<" words"<<endl;
      uint32_t N = x_i.n_cols;

      //DONE: this shuffle might not be working
      cout<<"x_i: "<<x_i.cols(0,10)<<endl;
      Mat<U> x_s = shuffle(x_i,1); // suffle the columns (words)
      cout<<"x_s: "<<x_s.cols(0,10)<<endl;
      Mat<U> x_te = x_s.cols(0,(N/2)-1) ; // select first half to train on
      Mat<U> x_ho = x_s.cols(N/2,N-1) ; // select second half as held out

      cout<<"x_te: "<<x_te.n_rows<<"x"<<x_te.n_cols<<endl;
      cout<<"x_ho: "<<x_ho.n_rows<<"x"<<x_ho.n_cols<<endl;

      mX_te.push_back(x_te); // on half of the data we train as usual to get a topic model for the document
      mX_ho.push_back(x_ho); // held out data to evaluate the perplexity
      return mX_ho.size();
    };

    //virtual Row<double> logP_w(uint32_t d) const=0;

    double perplexity(const Mat<U>& x_ho, const Row<double>& logP) const
    {
      assert(x_ho.n_rows==1);

      uint32_t N = x_ho.n_cols;
      double perp = 0.0;
      for (uint32_t i=0; i<N; ++i){
        //cout<<"c_z_n = "<<c[z[w]]<<" z_n="<<z[w]<<" w="<<w<<" N="<<N<<" x_w="<<x_ho[w]<<" topics.shape="<<topics.n_rows<<" "<<topics.n_cols;
          perp -= logP(x_ho(i));
        //cout<<"w="<<w<<"\tx_ho_w="<<x_ho[w]<<"\tlogP="<<logP[w]<<"\tperp+="<<-double(x_ho[w])*logP[w]<<endl;
      } cout<<endl;
      perp /= double(N);
      perp /= log(2.0); // since it is log base 2 in the perplexity formulation!
      perp = pow(2.0,perp);

      return perp;
    };

protected:

    const BaseMeasure<U>& mH; // base measure
    double mAlpha;
    double mOmega;
    vector<Mat<U> > mX; // training data
    vector<Mat<U> > mX_te; //  test data
    vector<Mat<U> > mX_ho; //  held out data

private:

};

template <class U>
class HDP_var_base
{
  public:

    HDP_var_base(uint32_t K, uint32_t T, uint32_t Nw)
      : mK(K), mT(T), mNw(Nw)
    {};

    /* Probability distribution over the words in document d
     *
     * TODO: so is that here not some MAP or ML estimate?!
     */
    Row<double> logP_w(uint32_t d) const {
      return logP_w(mPhi[d],mZeta[d],mGamma[d],mLambda);
    };

    Row<double> logP_w(const Mat<double>& phi, const Mat<double>& zeta, const Mat<double>& gamma, const Mat<double>& lambda) const
    {
      Row<double> p(mNw);
      p.zeros();

      Col<double> pi;
      Col<double> sigPi;
      Col<uint32_t> c;
      getDocTopics(pi,sigPi,c,gamma,zeta);
      Col<uint32_t> z(mNw);
      getWordTopics(z, phi);
      Mat<double> beta;
      getCorpTopic(beta,lambda);

      for (uint32_t w=0; w<mNw; ++w){
        p[w] = logCat(w, beta.row( c[ z[w] ]).t());
      }
      return p;
    };

//    void getA(Col<double>& a)
//    {
//      a=mA.col(0);
//    };
//
//    void getB(Col<double>& b)
//    {
//      b=mA.col(1);
//    };
//
//    bool getLambda(Col<double>& lambda, uint32_t k)
//    {
//      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
//      {
//        lambda=mLambda.row(k).t();
//        return true;
//      }else{
//        return false;
//      }
//    };
//
//    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, uint32_t d)
//    {
//      if (d < mGamma.size())
//        return getDocTopics(pi,sigPi,c,mGamma[d],mZeta[d]);
//      else{
//        cout<<"asking for out of range doc "<<d<<" have only "<<mGamma.size()<<endl;
//        return false;
//      }
//    };
//
//    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, const Mat<double>& gamma, const Mat<double>& zeta)
//    {
//      uint32_t T = gamma.n_rows; // doc level topics
//
//      sigPi.set_size(T+1);
//      pi.set_size(T);
//      c.set_size(T);
//
//      //cout<<"K="<<K<<" T="<<T<<endl;
//      betaMode(pi,gamma.col(0),gamma.col(1));
//      stickBreaking(sigPi,pi);
//      //cout<<"pi="<<pi<<endl;
//      //cout<<"sigPi="<<sigPi<<endl;
//      //cout<<"mGamma="<<mGamma[d]<<endl;
//      for (uint32_t i=0; i<T; ++i){
//        c[i] = multinomialMode(zeta.row(i));
//      }
//      return true;
//    };
//
//
//    bool getWordTopics(Col<uint32_t>& z, uint32_t d){
//      return getWordTopics(z,mPhi[d]);
//    };
//
//    bool getWordTopics(Col<uint32_t>& z, const Mat<double>& phi){
//      z.set_size(phi.n_rows);
//      for (uint32_t i=0; i<z.n_elem; ++i){
//        z[i] = multinomialMode(phi.row(i));
//      }
//      return true;
//    };
//
//    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV)
//    {
//      return getCorpTopicProportions(v,sigV,mA);
//    };
//
//    // a are the parameters of the beta distribution from which v is drawn
//    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV, const Mat<double>& a)
//    {
//      uint32_t K = a.n_rows; // corp level topics
//
//      sigV.set_size(K+1);
//      v.set_size(K);
//
//      betaMode(v, a.col(0), a.col(1));
//      stickBreaking(sigV,v);
//      return true;
//    };
//
//
//    bool getCorpTopic(Col<double>& topic, uint32_t k)
//    {
//      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
//      {
//        return getCorpTopic(topic,mLambda.row(k));
//      }else{
//        return false;
//      }
//    };
//
//    bool getCorpTopic(Col<double>& topic, const Row<double>& lambda)
//    {
//      // mode of dirichlet (MAP estimate)
//      dirMode(topic, lambda.t());
//      return true;
//    };
//
//    bool getCorpTopic(Mat<double>& topics, const Mat<double>& lambda)
//    {
//      uint32_t K = lambda.n_rows;
//      uint32_t Nw = lambda.n_cols;
//      topics.set_size(K,Nw);
//      for (uint32_t k=0; k<K; k++){
//        // mode of dirichlet (MAP estimate)
//        topics.row(k) = (lambda.row(k)-1.0)/sum(lambda.row(k)-1.0);
//        //dirMode(topics.row(k), lambda.row(k));
//      }
//      return true;
//    };
//

    void getA(Col<double>& a)
    {
      a=mA.col(0);
    };

    void getB(Col<double>& b)
    {
      b=mA.col(1);
    };

    bool getLambda(Col<double>& lambda, uint32_t k)
    {
      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
      {
        lambda=mLambda.row(k).t();
        return true;
      }else{
        return false;
      }
    };

    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, uint32_t d) const
    {
      if (d < mGamma.size())
        return getDocTopics(pi,sigPi,c,mGamma[d],mZeta[d]);
      else{
        cout<<"asking for out of range doc "<<d<<" have only "<<mGamma.size()<<endl;
        return false;
      }
    };

    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, const Mat<double>& gamma, const Mat<double>& zeta) const
    {
      uint32_t T = gamma.n_rows; // doc level topics

      sigPi.set_size(T+1);
      pi.set_size(T);
      c.set_size(T);

      //cout<<"K="<<K<<" T="<<T<<endl;
      betaMode(pi,gamma.col(0),gamma.col(1));
      stickBreaking(sigPi,pi);
      //cout<<"pi="<<pi<<endl;
      //cout<<"sigPi="<<sigPi<<endl;
      //cout<<"mGamma="<<mGamma[d]<<endl;
      for (uint32_t i=0; i<T; ++i){
        c[i] = multinomialMode(zeta.row(i));
      }
      return true;
    };

    bool getWordTopics(Col<uint32_t>& z, uint32_t d) const {
      return getWordTopics(z,mPhi[d]);
    };

    bool getWordTopics(Col<uint32_t>& z, const Mat<double>& phi) const {
      z.set_size(phi.n_rows);
      for (uint32_t i=0; i<z.n_elem; ++i){
        z[i] = multinomialMode(phi.row(i));
      }
      return true;
    };

    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV) const
    {
      return getCorpTopicProportions(v,sigV,mA);
    };

    /* a are the parameters of the beta distribution from which v is drawn
     *
     */
    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV, const Mat<double>& a) const
    {
      uint32_t K = a.n_rows; // corp level topics

      sigV.set_size(K+1);
      v.set_size(K);

      betaMode(v, a.col(0), a.col(1));
      stickBreaking(sigV,v);
      return true;
    };

    /* The mode of the estimate dirichlet distribution parameterized by lambda is used
     * as an estimate for the Multinomial distribution of the respective topics
     *
     */
    bool getCorpTopic(Col<double>& topic, uint32_t k) const
    {
      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
      {
        return getCorpTopic(topic,mLambda.row(k));
      }else{
        return false;
      }
    };

    bool getCorpTopic(Col<double>& topic, const Row<double>& lambda) const
    {
      // mode of dirichlet (MAP estimate)
      dirMode(topic, lambda.t());
      return true;
    };

    bool getCorpTopic(Mat<double>& topics, const Mat<double>& lambda) const
    {
      uint32_t K = lambda.n_rows;
      uint32_t Nw = lambda.n_cols;
      topics.set_size(K,Nw);
      for (uint32_t k=0; k<K; k++){
        // mode of dirichlet (MAP estimate)
        Row<double> lamb = lambda.row(k);
        Row<double> beta(Nw);
        dirMode(beta, lamb);
        topics.row(k) = beta;
//        cout<<"lambda_"<<k<<"="<<lambda.row(k)<<endl;
//        cout<<"topic_"<<k<<"="<<topics.row(k)<<endl;
//        cout<<"sum over topic_"<<k<<"="<<sum(topics.row(k))<<endl<<endl;
        //dirMode(topics.row(k), lambda.row(k));
      }
      return true;
    };

  protected:
    Mat<double> mLambda; // corpus level topics (Dirichlet)
    Mat<double> mA; // corpus level Beta process alpha parameter for stickbreaking
    vector<Mat<double> > mZeta; // document level topic indices/pointers to corpus level topics (Multinomial)
    vector<Mat<double> > mPhi; // document level word to doc level topic assignment (Multinomial)
    vector<Mat<double> > mGamma; // document level Beta distribution alpha parameter for stickbreaking

    Col<double> mPerp; // perplexity for each document

    uint32_t mT; // Doc level truncation
    uint32_t mK; // Corp level truncation
    uint32_t mNw; // size of dictionary

};

<commit_msg>hopefully fixed problem<commit_after>/* Copyright (c) 2012, Julian Straub <jstraub@csail.mit.edu>
 * Licensed under the MIT license. See LICENSE.txt or
 * http://www.opensource.org/licenses/mit-license.php */

#pragma once

#include "baseMeasure.hpp"
#include "probabilityHelpers.hpp"

#include <stddef.h>
#include <stdint.h>
#include <typeinfo>

#include <armadillo>

using namespace std;
using namespace arma;

template <class U>
class HDP // : public DP<U>
{
  public:
    HDP(const BaseMeasure<U>& base, double alpha, double omega)
      : mH(base), mAlpha(alpha), mOmega(omega)
    { };

    ~HDP()
    {	};

    /*
     * interface mainly for python
     * @return the index of the added x_i in the set of all documents
     */
    uint32_t addDoc(const Mat<U>& x_i)
    {
      mX.push_back(x_i);
      return mX.size()-1;
    };

    // interface mainly for python
    uint32_t addHeldOut(const Mat<U>& x_i)
    {
      //cout<<"added heldout doc with "<<x_i.size()<<" words"<<endl;
      uint32_t N = x_i.n_cols;

      //DONE: this shuffle might not be working
      cout<<"x_i: "<<x_i.cols(0,10)<<endl;
      Mat<U> x_s = shuffle(x_i,1); // suffle the columns (words)
      cout<<"x_s: "<<x_s.cols(0,10)<<endl;
      Mat<U> x_te = x_s.cols(0,(N/2)-1) ; // select first half to train on
      Mat<U> x_ho = x_s.cols(N/2,N-1) ; // select second half as held out

      cout<<"x_te: "<<x_te.n_rows<<"x"<<x_te.n_cols<<endl;
      cout<<"x_ho: "<<x_ho.n_rows<<"x"<<x_ho.n_cols<<endl;

      mX_te.push_back(x_te); // on half of the data we train as usual to get a topic model for the document
      mX_ho.push_back(x_ho); // held out data to evaluate the perplexity
      return mX_ho.size();
    };

    //virtual Row<double> logP_w(uint32_t d) const=0;

    double perplexity(const Mat<U>& x_ho, const Row<double>& logP) const
    {
      assert(x_ho.n_rows==1);

      uint32_t N = x_ho.n_cols;
      double perp = 0.0;
      for (uint32_t i=0; i<N; ++i){
        //cout<<"c_z_n = "<<c[z[w]]<<" z_n="<<z[w]<<" w="<<w<<" N="<<N<<" x_w="<<x_ho[w]<<" topics.shape="<<topics.n_rows<<" "<<topics.n_cols;
        cout<<"x_ho_i="<<x_ho(i)<<"; logP_x_ho_i="<<logP(x_ho(i))<<endl;
          perp -= logP(x_ho(i));
        //cout<<"w="<<w<<"\tx_ho_w="<<x_ho[w]<<"\tlogP="<<logP[w]<<"\tperp+="<<-double(x_ho[w])*logP[w]<<endl;
      } cout<<endl;
      perp /= double(N);
      perp /= log(2.0); // since it is log base 2 in the perplexity formulation!
      perp = pow(2.0,perp);

      return perp;
    };

protected:

    const BaseMeasure<U>& mH; // base measure
    double mAlpha;
    double mOmega;
    vector<Mat<U> > mX; // training data
    vector<Mat<U> > mX_te; //  test data
    vector<Mat<U> > mX_ho; //  held out data

private:

};

template <class U>
class HDP_var_base
{
  public:

    HDP_var_base(uint32_t K, uint32_t T, uint32_t Nw)
      : mK(K), mT(T), mNw(Nw)
    {};

    /* Probability distribution over the words in document d
     *
     * TODO: so is that here not some MAP or ML estimate?!
     */
    Row<double> logP_w(uint32_t d) const {
      return logP_w(mPhi[d],mZeta[d],mGamma[d],mLambda);
    };

    Row<double> logP_w(const Mat<double>& phi, const Mat<double>& zeta, const Mat<double>& gamma, const Mat<double>& lambda) const
    {
      Row<double> p(mNw);
      p.zeros();

      Col<double> pi;
      Col<double> sigPi;
      Col<uint32_t> c;
      getDocTopics(pi,sigPi,c,gamma,zeta);
      Col<uint32_t> z(mNw);
      getWordTopics(z, phi);
      Mat<double> beta;
      getCorpTopic(beta,lambda);

      for (uint32_t w=0; w<mNw; ++w){
        p[w] = logCat(w, beta.row( c[ z[w] ]));
      }
      cout<<"p="<<p<<endl;
      return p;
    };

//    void getA(Col<double>& a)
//    {
//      a=mA.col(0);
//    };
//
//    void getB(Col<double>& b)
//    {
//      b=mA.col(1);
//    };
//
//    bool getLambda(Col<double>& lambda, uint32_t k)
//    {
//      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
//      {
//        lambda=mLambda.row(k).t();
//        return true;
//      }else{
//        return false;
//      }
//    };
//
//    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, uint32_t d)
//    {
//      if (d < mGamma.size())
//        return getDocTopics(pi,sigPi,c,mGamma[d],mZeta[d]);
//      else{
//        cout<<"asking for out of range doc "<<d<<" have only "<<mGamma.size()<<endl;
//        return false;
//      }
//    };
//
//    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, const Mat<double>& gamma, const Mat<double>& zeta)
//    {
//      uint32_t T = gamma.n_rows; // doc level topics
//
//      sigPi.set_size(T+1);
//      pi.set_size(T);
//      c.set_size(T);
//
//      //cout<<"K="<<K<<" T="<<T<<endl;
//      betaMode(pi,gamma.col(0),gamma.col(1));
//      stickBreaking(sigPi,pi);
//      //cout<<"pi="<<pi<<endl;
//      //cout<<"sigPi="<<sigPi<<endl;
//      //cout<<"mGamma="<<mGamma[d]<<endl;
//      for (uint32_t i=0; i<T; ++i){
//        c[i] = multinomialMode(zeta.row(i));
//      }
//      return true;
//    };
//
//
//    bool getWordTopics(Col<uint32_t>& z, uint32_t d){
//      return getWordTopics(z,mPhi[d]);
//    };
//
//    bool getWordTopics(Col<uint32_t>& z, const Mat<double>& phi){
//      z.set_size(phi.n_rows);
//      for (uint32_t i=0; i<z.n_elem; ++i){
//        z[i] = multinomialMode(phi.row(i));
//      }
//      return true;
//    };
//
//    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV)
//    {
//      return getCorpTopicProportions(v,sigV,mA);
//    };
//
//    // a are the parameters of the beta distribution from which v is drawn
//    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV, const Mat<double>& a)
//    {
//      uint32_t K = a.n_rows; // corp level topics
//
//      sigV.set_size(K+1);
//      v.set_size(K);
//
//      betaMode(v, a.col(0), a.col(1));
//      stickBreaking(sigV,v);
//      return true;
//    };
//
//
//    bool getCorpTopic(Col<double>& topic, uint32_t k)
//    {
//      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
//      {
//        return getCorpTopic(topic,mLambda.row(k));
//      }else{
//        return false;
//      }
//    };
//
//    bool getCorpTopic(Col<double>& topic, const Row<double>& lambda)
//    {
//      // mode of dirichlet (MAP estimate)
//      dirMode(topic, lambda.t());
//      return true;
//    };
//
//    bool getCorpTopic(Mat<double>& topics, const Mat<double>& lambda)
//    {
//      uint32_t K = lambda.n_rows;
//      uint32_t Nw = lambda.n_cols;
//      topics.set_size(K,Nw);
//      for (uint32_t k=0; k<K; k++){
//        // mode of dirichlet (MAP estimate)
//        topics.row(k) = (lambda.row(k)-1.0)/sum(lambda.row(k)-1.0);
//        //dirMode(topics.row(k), lambda.row(k));
//      }
//      return true;
//    };
//

    void getA(Col<double>& a)
    {
      a=mA.col(0);
    };

    void getB(Col<double>& b)
    {
      b=mA.col(1);
    };

    bool getLambda(Col<double>& lambda, uint32_t k)
    {
      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
      {
        lambda=mLambda.row(k).t();
        return true;
      }else{
        return false;
      }
    };

    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, uint32_t d) const
    {
      if (d < mGamma.size())
        return getDocTopics(pi,sigPi,c,mGamma[d],mZeta[d]);
      else{
        cout<<"asking for out of range doc "<<d<<" have only "<<mGamma.size()<<endl;
        return false;
      }
    };

    bool getDocTopics(Col<double>& pi, Col<double>& sigPi, Col<uint32_t>& c, const Mat<double>& gamma, const Mat<double>& zeta) const
    {
      uint32_t T = gamma.n_rows; // doc level topics

      sigPi.set_size(T+1);
      pi.set_size(T);
      c.set_size(T);

      //cout<<"K="<<K<<" T="<<T<<endl;
      betaMode(pi,gamma.col(0),gamma.col(1));
      stickBreaking(sigPi,pi);
      //cout<<"pi="<<pi<<endl;
      //cout<<"sigPi="<<sigPi<<endl;
      //cout<<"mGamma="<<mGamma[d]<<endl;
      for (uint32_t i=0; i<T; ++i){
        c[i] = multinomialMode(zeta.row(i));
      }
      return true;
    };

    bool getWordTopics(Col<uint32_t>& z, uint32_t d) const {
      return getWordTopics(z,mPhi[d]);
    };

    bool getWordTopics(Col<uint32_t>& z, const Mat<double>& phi) const {
      z.set_size(phi.n_rows);
      for (uint32_t i=0; i<z.n_elem; ++i){
        z[i] = multinomialMode(phi.row(i));
      }
      return true;
    };

    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV) const
    {
      return getCorpTopicProportions(v,sigV,mA);
    };

    /* a are the parameters of the beta distribution from which v is drawn
     *
     */
    bool getCorpTopicProportions(Col<double>& v, Col<double>& sigV, const Mat<double>& a) const
    {
      uint32_t K = a.n_rows; // corp level topics

      sigV.set_size(K+1);
      v.set_size(K);

      betaMode(v, a.col(0), a.col(1));
      stickBreaking(sigV,v);
      return true;
    };

    /* The mode of the estimate dirichlet distribution parameterized by lambda is used
     * as an estimate for the Multinomial distribution of the respective topics
     *
     */
    bool getCorpTopic(Col<double>& topic, uint32_t k) const
    {
      if(mLambda.n_rows > 0 && k < mLambda.n_rows)
      {
        return getCorpTopic(topic,mLambda.row(k));
      }else{
        return false;
      }
    };

    bool getCorpTopic(Col<double>& topic, const Row<double>& lambda) const
    {
      // mode of dirichlet (MAP estimate)
      dirMode(topic, lambda.t());
      return true;
    };

    bool getCorpTopic(Mat<double>& topics, const Mat<double>& lambda) const
    {
      uint32_t K = lambda.n_rows;
      uint32_t Nw = lambda.n_cols;
      topics.set_size(K,Nw);
      for (uint32_t k=0; k<K; k++){
        // mode of dirichlet (MAP estimate)
        Row<double> lamb = lambda.row(k);
        Row<double> beta(Nw);
        dirMode(beta, lamb);
        topics.row(k) = beta;
//        cout<<"lambda_"<<k<<"="<<lambda.row(k)<<endl;
//        cout<<"topic_"<<k<<"="<<topics.row(k)<<endl;
//        cout<<"sum over topic_"<<k<<"="<<sum(topics.row(k))<<endl<<endl;
        //dirMode(topics.row(k), lambda.row(k));
      }
      return true;
    };

  protected:
    Mat<double> mLambda; // corpus level topics (Dirichlet)
    Mat<double> mA; // corpus level Beta process alpha parameter for stickbreaking
    vector<Mat<double> > mZeta; // document level topic indices/pointers to corpus level topics (Multinomial)
    vector<Mat<double> > mPhi; // document level word to doc level topic assignment (Multinomial)
    vector<Mat<double> > mGamma; // document level Beta distribution alpha parameter for stickbreaking

    Col<double> mPerp; // perplexity for each document

    uint32_t mT; // Doc level truncation
    uint32_t mK; // Corp level truncation
    uint32_t mNw; // size of dictionary

};

<|endoftext|>


<commit_before>#include "zookeeper_cc_util/zookeeper_cc_util.h"

#include <stdlib.h>
#include <string>
#include <iostream>
#include <sstream>
#include <gtest/gtest.h>

using zookeeper_cc_util::Zookeeper;

namespace {

const int kRecvTimeoutMs = 1000;

}

class ZookeeperCcUtilTest : public ::testing::Test {
 protected:
  virtual void SetUp() override {
    char *hosts = getenv("ZOOKEEPER_TEST_HOSTS");
    ASSERT_TRUE(hosts && strlen(hosts) > 0) << "ZOOKEEPER_TEST_HOSTS is unspecified";

    // Construct random path inside Zookeeper to provide some tests isolation.
    auto unit_test = ::testing::UnitTest::GetInstance();
    const ::testing::TestInfo* const test_info =
        unit_test->current_test_info();
    std::stringstream bases;
    bases << "/zookeeper-cc-util-test"
          << "/" << unit_test->random_seed()
          << "/" << test_info->test_case_name()
          << "/" << test_info->name();
    std::string base = bases.str();

    // Disable most logging.
    zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);

    zk_.reset(new Zookeeper(hosts, kRecvTimeoutMs, base));
  }

  virtual void TearDown() override {
    zk_.reset();
  }

  std::unique_ptr<Zookeeper> zk_;
};

TEST_F(ZookeeperCcUtilTest, EnforceBasePathAndExists) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("", &ZOO_OPEN_ACL_UNSAFE));

  EXPECT_EQ(ZOK, zk_->Exists("", nullptr, nullptr));
}

TEST_F(ZookeeperCcUtilTest, GetCreateGet) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("", &ZOO_OPEN_ACL_UNSAFE));

  std::string data = "not_modified";

  EXPECT_EQ(ZNONODE, zk_->Get("some_node", &data, nullptr, nullptr));
  EXPECT_EQ("not_modified", data);

  EXPECT_EQ(ZOK, zk_->Create("some_node", "some_value", false, &ZOO_OPEN_ACL_UNSAFE));

  EXPECT_EQ(ZOK, zk_->Get("some_node", &data, nullptr, nullptr));
  EXPECT_EQ("some_value", data);
}
<commit_msg>model-server/zookeeper_cc_util_test: add tests for EnsureTrailingSlash, GetLastPathSegment, all operations (no watchers yet)<commit_after>#include "zookeeper_cc_util/zookeeper_cc_util.h"

#include <stdlib.h>
#include <string>
#include <iostream>
#include <sstream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

using zookeeper_cc_util::Zookeeper;
using zookeeper_cc_util::EnsureTrailingSlash;
using zookeeper_cc_util::GetLastPathSegment;
using ::testing::UnorderedElementsAre;
using ::testing::StrEq;

namespace {

const int kRecvTimeoutMs = 1000;

}

TEST(ZookeeperCcUtilEnsureTrailingSlashTest, EmptyString) {
  EXPECT_EQ("/", EnsureTrailingSlash(""));
}

TEST(ZookeeperCcUtilEnsureTrailingSlashTest, SingleSlash) {
  EXPECT_EQ("/", EnsureTrailingSlash("/"));
}

TEST(ZookeeperCcUtilEnsureTrailingSlashTest, SeveralNodesNoTrailingSlash) {
  EXPECT_EQ("/node1/node2/", EnsureTrailingSlash("/node1/node2"));
}

TEST(ZookeeperCcUtilEnsureTrailingSlashTest, SeveralNodesWithTrailingSlash) {
  EXPECT_EQ("/node1/node2/", EnsureTrailingSlash("/node1/node2/"));
}

TEST(ZookeeperCcUtilGetLastPathSegmentTest, EmptyString) {
  EXPECT_THAT(GetLastPathSegment(""), StrEq(""));
}

TEST(ZookeeperCcUtilGetLastPathSegmentTest, SingleNode) {
  EXPECT_THAT(GetLastPathSegment("node"), StrEq("node"));
}

TEST(ZookeeperCcUtilGetLastPathSegmentTest, SingleNodeStartsWithSlash) {
  EXPECT_THAT(GetLastPathSegment("/node"), StrEq("node"));
}

TEST(ZookeeperCcUtilGetLastPathSegmentTest, MultipleNodes) {
  EXPECT_THAT(GetLastPathSegment("/node1/node2"), StrEq("node2"));
}

class ZookeeperCcUtilTest : public ::testing::Test {
 protected:
  virtual void SetUp() override {
    char *hosts = getenv("ZOOKEEPER_TEST_HOSTS");
    ASSERT_TRUE(hosts && strlen(hosts) > 0) << "ZOOKEEPER_TEST_HOSTS is unspecified";

    // Construct random path inside Zookeeper to provide some tests isolation.
    auto unit_test = ::testing::UnitTest::GetInstance();
    const ::testing::TestInfo* const test_info =
        unit_test->current_test_info();
    std::stringstream bases;
    bases << "/zookeeper-cc-util-test"
          << "/" << unit_test->random_seed()
          << "/" << test_info->test_case_name()
          << "/" << test_info->name();
    std::string base = bases.str();

    // Disable most logging.
    zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);

    zk_.reset(new Zookeeper(hosts, kRecvTimeoutMs, base));
  }

  virtual void TearDown() override {
    zk_.reset();
  }

  std::unique_ptr<Zookeeper> zk_;
};

TEST_F(ZookeeperCcUtilTest, EnforceBasePathAndExists) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("", &ZOO_OPEN_ACL_UNSAFE));

  EXPECT_EQ(ZOK, zk_->Exists("", nullptr, nullptr));
}

TEST_F(ZookeeperCcUtilTest, EnforceNodeAndExists) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("some_node", &ZOO_OPEN_ACL_UNSAFE));

  EXPECT_EQ(ZOK, zk_->Exists("some_node", nullptr, nullptr));
}

TEST_F(ZookeeperCcUtilTest, NodeNotExists) {
  ASSERT_TRUE(zk_->Init());

  EXPECT_EQ(ZNONODE, zk_->Exists("some_node", nullptr, nullptr));
}

TEST_F(ZookeeperCcUtilTest, GetCreateGet) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("", &ZOO_OPEN_ACL_UNSAFE));

  std::string data = "not_modified";

  EXPECT_EQ(ZNONODE, zk_->Get("some_node", &data, nullptr, nullptr));
  EXPECT_EQ("not_modified", data);

  EXPECT_EQ(ZOK, zk_->Create("some_node", "some_value", false, &ZOO_OPEN_ACL_UNSAFE));

  EXPECT_EQ(ZOK, zk_->Get("some_node", &data, nullptr, nullptr));
  EXPECT_EQ("some_value", data);
}

TEST_F(ZookeeperCcUtilTest, SetGet) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("some_node", &ZOO_OPEN_ACL_UNSAFE));

  EXPECT_EQ(ZOK, zk_->Set("some_node", "some_value"));

  std::string data;
  EXPECT_EQ(ZOK, zk_->Get("some_node", &data, nullptr, nullptr));
  EXPECT_EQ("some_value", data);
}

TEST_F(ZookeeperCcUtilTest, GetChildren) {
  ASSERT_TRUE(zk_->Init());
  ASSERT_EQ(ZOK, zk_->EnforcePath("node1/1", &ZOO_OPEN_ACL_UNSAFE));
  ASSERT_EQ(ZOK, zk_->EnforcePath("node1/2", &ZOO_OPEN_ACL_UNSAFE));
  ASSERT_EQ(ZOK, zk_->EnforcePath("node2/3", &ZOO_OPEN_ACL_UNSAFE));
  ASSERT_EQ(ZOK, zk_->EnforcePath("node2/4", &ZOO_OPEN_ACL_UNSAFE));

  std::vector<std::string> children;
  EXPECT_EQ(ZOK, zk_->GetChildren("node1", &children, nullptr));
  EXPECT_THAT(children, UnorderedElementsAre("1", "2"));

  EXPECT_EQ(ZOK, zk_->GetChildren("node2", &children, nullptr));
  EXPECT_THAT(children, UnorderedElementsAre("3", "4"));

  EXPECT_EQ(ZOK, zk_->GetChildren("", &children, nullptr));
  EXPECT_THAT(children, UnorderedElementsAre("node1", "node2"));
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_coding/neteq4/decoder_database.h"

#include <assert.h>
#include <stdlib.h>

#include <string>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "webrtc/modules/audio_coding/neteq4/mock/mock_audio_decoder.h"
#include "webrtc/test/testsupport/gtest_disable.h"

namespace webrtc {

TEST(DecoderDatabase, CreateAndDestroy) {
  DecoderDatabase db;
  EXPECT_EQ(0, db.Size());
  EXPECT_TRUE(db.Empty());
}

TEST(DecoderDatabase, InsertAndRemove) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCMu));
  EXPECT_EQ(1, db.Size());
  EXPECT_FALSE(db.Empty());
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType));
  EXPECT_EQ(0, db.Size());
  EXPECT_TRUE(db.Empty());
}

TEST(DecoderDatabase, GetDecoderInfo) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCMu));
  const DecoderDatabase::DecoderInfo* info;
  info = db.GetDecoderInfo(kPayloadType);
  ASSERT_TRUE(info != NULL);
  EXPECT_EQ(kDecoderPCMu, info->codec_type);
  EXPECT_EQ(NULL, info->decoder);
  EXPECT_EQ(8000, info->fs_hz);
  EXPECT_FALSE(info->external);
  info = db.GetDecoderInfo(kPayloadType + 1);  // Other payload type.
  EXPECT_TRUE(info == NULL);  // Should not be found.
}

TEST(DecoderDatabase, GetRtpPayloadType) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCMu));
  EXPECT_EQ(kPayloadType, db.GetRtpPayloadType(kDecoderPCMu));
  const uint8_t expected_value = DecoderDatabase::kRtpPayloadTypeError;
  EXPECT_EQ(expected_value,
            db.GetRtpPayloadType(kDecoderISAC));  // iSAC is not registered.
}

TEST(DecoderDatabase, DISABLED_ON_ANDROID(GetDecoder)) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderILBC));
  AudioDecoder* dec = db.GetDecoder(kPayloadType);
  ASSERT_TRUE(dec != NULL);
}

TEST(DecoderDatabase, TypeTests) {
  DecoderDatabase db;
  const uint8_t kPayloadTypePcmU = 0;
  const uint8_t kPayloadTypeCng = 13;
  const uint8_t kPayloadTypeDtmf = 100;
  const uint8_t kPayloadTypeRed = 101;
  const uint8_t kPayloadNotUsed = 102;
  // Load into database.
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypePcmU, kDecoderPCMu));
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypeCng, kDecoderCNGnb));
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypeDtmf, kDecoderAVT));
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypeRed, kDecoderRED));
  EXPECT_EQ(4, db.Size());
  // Test.
  EXPECT_FALSE(db.IsComfortNoise(kPayloadNotUsed));
  EXPECT_FALSE(db.IsDtmf(kPayloadNotUsed));
  EXPECT_FALSE(db.IsRed(kPayloadNotUsed));
  EXPECT_FALSE(db.IsComfortNoise(kPayloadTypePcmU));
  EXPECT_FALSE(db.IsDtmf(kPayloadTypePcmU));
  EXPECT_FALSE(db.IsRed(kPayloadTypePcmU));
  EXPECT_FALSE(db.IsType(kPayloadTypePcmU, kDecoderISAC));
  EXPECT_TRUE(db.IsType(kPayloadTypePcmU, kDecoderPCMu));
  EXPECT_TRUE(db.IsComfortNoise(kPayloadTypeCng));
  EXPECT_TRUE(db.IsDtmf(kPayloadTypeDtmf));
  EXPECT_TRUE(db.IsRed(kPayloadTypeRed));
}

TEST(DecoderDatabase, ExternalDecoder) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  MockAudioDecoder decoder;
  // Load into database.
  EXPECT_EQ(DecoderDatabase::kOK,
            db.InsertExternal(kPayloadType, kDecoderPCMu, 8000,
                               &decoder));
  EXPECT_EQ(1, db.Size());
  // Get decoder and make sure we get the external one.
  EXPECT_EQ(&decoder, db.GetDecoder(kPayloadType));
  // Get the decoder info struct and check it too.
  const DecoderDatabase::DecoderInfo* info;
  info = db.GetDecoderInfo(kPayloadType);
  ASSERT_TRUE(info != NULL);
  EXPECT_EQ(kDecoderPCMu, info->codec_type);
  EXPECT_EQ(&decoder, info->decoder);
  EXPECT_EQ(8000, info->fs_hz);
  EXPECT_TRUE(info->external);
  // Expect not to delete the decoder when removing it from the database, since
  // it was declared externally.
  EXPECT_CALL(decoder, Die()).Times(0);
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType));
  EXPECT_TRUE(db.Empty());

  EXPECT_CALL(decoder, Die()).Times(1);  // Will be called when |db| is deleted.
}

TEST(DecoderDatabase, CheckPayloadTypes) {
  DecoderDatabase db;
  // Load a number of payloads into the database. Payload types are 0, 1, ...,
  // while the decoder type is the same for all payload types (this does not
  // matter for the test).
  const int kNumPayloads = 10;
  for (uint8_t payload_type = 0; payload_type < kNumPayloads; ++payload_type) {
    EXPECT_EQ(DecoderDatabase::kOK,
              db.RegisterPayload(payload_type, kDecoderArbitrary));
  }
  PacketList packet_list;
  for (int i = 0; i < kNumPayloads + 1; ++i) {
    // Create packet with payload type |i|. The last packet will have a payload
    // type that is not registered in the decoder database.
    Packet* packet = new Packet;
    packet->header.payloadType = i;
    packet_list.push_back(packet);
  }

  // Expect to return false, since the last packet is of an unknown type.
  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
            db.CheckPayloadTypes(packet_list));

  delete packet_list.back();
  packet_list.pop_back();  // Remove the unknown one.

  EXPECT_EQ(DecoderDatabase::kOK, db.CheckPayloadTypes(packet_list));

  // Delete all packets.
  PacketList::iterator it = packet_list.begin();
  while (it != packet_list.end()) {
    delete packet_list.front();
    it = packet_list.erase(it);
  }
}

// Test the methods for setting and getting active speech and CNG decoders.
TEST(DecoderDatabase, ActiveDecoders) {
  DecoderDatabase db;
  // Load payload types.
  ASSERT_EQ(DecoderDatabase::kOK, db.RegisterPayload(0, kDecoderPCMu));
  ASSERT_EQ(DecoderDatabase::kOK, db.RegisterPayload(103, kDecoderISAC));
  ASSERT_EQ(DecoderDatabase::kOK, db.RegisterPayload(13, kDecoderCNGnb));
  // Verify that no decoders are active from the start.
  EXPECT_EQ(NULL, db.GetActiveDecoder());
  EXPECT_EQ(NULL, db.GetActiveCngDecoder());

  // Set active speech codec.
  bool changed;  // Should be true when the active decoder changed.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(0, &changed));
  EXPECT_TRUE(changed);
  AudioDecoder* decoder = db.GetActiveDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderPCMu, decoder->codec_type());

  // Set the same again. Expect no change.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(0, &changed));
  EXPECT_FALSE(changed);
  decoder = db.GetActiveDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderPCMu, decoder->codec_type());

  // Change active decoder.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(103, &changed));
  EXPECT_TRUE(changed);
  decoder = db.GetActiveDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderISAC, decoder->codec_type());

  // Remove the active decoder, and verify that the active becomes NULL.
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(103));
  EXPECT_EQ(NULL, db.GetActiveDecoder());

  // Set active CNG codec.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveCngDecoder(13));
  decoder = db.GetActiveCngDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderCNGnb, decoder->codec_type());

  // Remove the active CNG decoder, and verify that the active becomes NULL.
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(13));
  EXPECT_EQ(NULL, db.GetActiveCngDecoder());

  // Try to set non-existing codecs as active.
  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
            db.SetActiveDecoder(17, &changed));
  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
            db.SetActiveCngDecoder(17));
}
}  // namespace webrtc
<commit_msg>Re-enable NetEQ DecoderDatabase test for Android<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_coding/neteq4/decoder_database.h"

#include <assert.h>
#include <stdlib.h>

#include <string>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "webrtc/modules/audio_coding/neteq4/mock/mock_audio_decoder.h"
#include "webrtc/test/testsupport/gtest_disable.h"

namespace webrtc {

TEST(DecoderDatabase, CreateAndDestroy) {
  DecoderDatabase db;
  EXPECT_EQ(0, db.Size());
  EXPECT_TRUE(db.Empty());
}

TEST(DecoderDatabase, InsertAndRemove) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCMu));
  EXPECT_EQ(1, db.Size());
  EXPECT_FALSE(db.Empty());
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType));
  EXPECT_EQ(0, db.Size());
  EXPECT_TRUE(db.Empty());
}

TEST(DecoderDatabase, GetDecoderInfo) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCMu));
  const DecoderDatabase::DecoderInfo* info;
  info = db.GetDecoderInfo(kPayloadType);
  ASSERT_TRUE(info != NULL);
  EXPECT_EQ(kDecoderPCMu, info->codec_type);
  EXPECT_EQ(NULL, info->decoder);
  EXPECT_EQ(8000, info->fs_hz);
  EXPECT_FALSE(info->external);
  info = db.GetDecoderInfo(kPayloadType + 1);  // Other payload type.
  EXPECT_TRUE(info == NULL);  // Should not be found.
}

TEST(DecoderDatabase, GetRtpPayloadType) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCMu));
  EXPECT_EQ(kPayloadType, db.GetRtpPayloadType(kDecoderPCMu));
  const uint8_t expected_value = DecoderDatabase::kRtpPayloadTypeError;
  EXPECT_EQ(expected_value,
            db.GetRtpPayloadType(kDecoderISAC));  // iSAC is not registered.
}

TEST(DecoderDatabase, GetDecoder) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadType, kDecoderPCM16B));
  AudioDecoder* dec = db.GetDecoder(kPayloadType);
  ASSERT_TRUE(dec != NULL);
}

TEST(DecoderDatabase, TypeTests) {
  DecoderDatabase db;
  const uint8_t kPayloadTypePcmU = 0;
  const uint8_t kPayloadTypeCng = 13;
  const uint8_t kPayloadTypeDtmf = 100;
  const uint8_t kPayloadTypeRed = 101;
  const uint8_t kPayloadNotUsed = 102;
  // Load into database.
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypePcmU, kDecoderPCMu));
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypeCng, kDecoderCNGnb));
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypeDtmf, kDecoderAVT));
  EXPECT_EQ(DecoderDatabase::kOK,
            db.RegisterPayload(kPayloadTypeRed, kDecoderRED));
  EXPECT_EQ(4, db.Size());
  // Test.
  EXPECT_FALSE(db.IsComfortNoise(kPayloadNotUsed));
  EXPECT_FALSE(db.IsDtmf(kPayloadNotUsed));
  EXPECT_FALSE(db.IsRed(kPayloadNotUsed));
  EXPECT_FALSE(db.IsComfortNoise(kPayloadTypePcmU));
  EXPECT_FALSE(db.IsDtmf(kPayloadTypePcmU));
  EXPECT_FALSE(db.IsRed(kPayloadTypePcmU));
  EXPECT_FALSE(db.IsType(kPayloadTypePcmU, kDecoderISAC));
  EXPECT_TRUE(db.IsType(kPayloadTypePcmU, kDecoderPCMu));
  EXPECT_TRUE(db.IsComfortNoise(kPayloadTypeCng));
  EXPECT_TRUE(db.IsDtmf(kPayloadTypeDtmf));
  EXPECT_TRUE(db.IsRed(kPayloadTypeRed));
}

TEST(DecoderDatabase, ExternalDecoder) {
  DecoderDatabase db;
  const uint8_t kPayloadType = 0;
  MockAudioDecoder decoder;
  // Load into database.
  EXPECT_EQ(DecoderDatabase::kOK,
            db.InsertExternal(kPayloadType, kDecoderPCMu, 8000,
                               &decoder));
  EXPECT_EQ(1, db.Size());
  // Get decoder and make sure we get the external one.
  EXPECT_EQ(&decoder, db.GetDecoder(kPayloadType));
  // Get the decoder info struct and check it too.
  const DecoderDatabase::DecoderInfo* info;
  info = db.GetDecoderInfo(kPayloadType);
  ASSERT_TRUE(info != NULL);
  EXPECT_EQ(kDecoderPCMu, info->codec_type);
  EXPECT_EQ(&decoder, info->decoder);
  EXPECT_EQ(8000, info->fs_hz);
  EXPECT_TRUE(info->external);
  // Expect not to delete the decoder when removing it from the database, since
  // it was declared externally.
  EXPECT_CALL(decoder, Die()).Times(0);
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType));
  EXPECT_TRUE(db.Empty());

  EXPECT_CALL(decoder, Die()).Times(1);  // Will be called when |db| is deleted.
}

TEST(DecoderDatabase, CheckPayloadTypes) {
  DecoderDatabase db;
  // Load a number of payloads into the database. Payload types are 0, 1, ...,
  // while the decoder type is the same for all payload types (this does not
  // matter for the test).
  const int kNumPayloads = 10;
  for (uint8_t payload_type = 0; payload_type < kNumPayloads; ++payload_type) {
    EXPECT_EQ(DecoderDatabase::kOK,
              db.RegisterPayload(payload_type, kDecoderArbitrary));
  }
  PacketList packet_list;
  for (int i = 0; i < kNumPayloads + 1; ++i) {
    // Create packet with payload type |i|. The last packet will have a payload
    // type that is not registered in the decoder database.
    Packet* packet = new Packet;
    packet->header.payloadType = i;
    packet_list.push_back(packet);
  }

  // Expect to return false, since the last packet is of an unknown type.
  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
            db.CheckPayloadTypes(packet_list));

  delete packet_list.back();
  packet_list.pop_back();  // Remove the unknown one.

  EXPECT_EQ(DecoderDatabase::kOK, db.CheckPayloadTypes(packet_list));

  // Delete all packets.
  PacketList::iterator it = packet_list.begin();
  while (it != packet_list.end()) {
    delete packet_list.front();
    it = packet_list.erase(it);
  }
}

// Test the methods for setting and getting active speech and CNG decoders.
TEST(DecoderDatabase, ActiveDecoders) {
  DecoderDatabase db;
  // Load payload types.
  ASSERT_EQ(DecoderDatabase::kOK, db.RegisterPayload(0, kDecoderPCMu));
  ASSERT_EQ(DecoderDatabase::kOK, db.RegisterPayload(103, kDecoderISAC));
  ASSERT_EQ(DecoderDatabase::kOK, db.RegisterPayload(13, kDecoderCNGnb));
  // Verify that no decoders are active from the start.
  EXPECT_EQ(NULL, db.GetActiveDecoder());
  EXPECT_EQ(NULL, db.GetActiveCngDecoder());

  // Set active speech codec.
  bool changed;  // Should be true when the active decoder changed.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(0, &changed));
  EXPECT_TRUE(changed);
  AudioDecoder* decoder = db.GetActiveDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderPCMu, decoder->codec_type());

  // Set the same again. Expect no change.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(0, &changed));
  EXPECT_FALSE(changed);
  decoder = db.GetActiveDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderPCMu, decoder->codec_type());

  // Change active decoder.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(103, &changed));
  EXPECT_TRUE(changed);
  decoder = db.GetActiveDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderISAC, decoder->codec_type());

  // Remove the active decoder, and verify that the active becomes NULL.
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(103));
  EXPECT_EQ(NULL, db.GetActiveDecoder());

  // Set active CNG codec.
  EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveCngDecoder(13));
  decoder = db.GetActiveCngDecoder();
  ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
  EXPECT_EQ(kDecoderCNGnb, decoder->codec_type());

  // Remove the active CNG decoder, and verify that the active becomes NULL.
  EXPECT_EQ(DecoderDatabase::kOK, db.Remove(13));
  EXPECT_EQ(NULL, db.GetActiveCngDecoder());

  // Try to set non-existing codecs as active.
  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
            db.SetActiveDecoder(17, &changed));
  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
            db.SetActiveCngDecoder(17));
}
}  // namespace webrtc
<|endoftext|>


<commit_before>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

#include "Exception.h"

#include <cassert>

using namespace aud;

#define AUD_CAPI_IMPLEMENTATION
#include "AUD_Convolution.h"

extern AUD_API AUD_HRTF* AUD_HRTF_create()
{
	try
	{
		return new AUD_HRTF(new HRTF());
	}
	catch(Exception&)
	{
		return nullptr;
	}
}

extern AUD_API void AUD_HRTF_free(AUD_HRTF* hrtfs)
{
	assert(hrtfs);
	delete hrtfs;
}

extern AUD_API void AUD_HRTF_addImpulseResponse(AUD_HRTF* hrtfs, AUD_Sound* sound, float azimuth, float elevation)
{
	assert(hrtfs);
	assert(filter);

	(*hrtfs)->addImpulseResponse(std::make_shared<StreamBuffer>(*sound), azimuth, elevation);
}

extern AUD_API AUD_Source* AUD_Source_create(float azimuth, float elevation, float distance)
{
	try
	{
		return new AUD_Source(new Source(azimuth, elevation, distance));
	}
	catch(Exception&)
	{
		return nullptr;
	}
}

extern AUD_API void AUD_Source_free(AUD_Source* source)
{
	assert(source);
	delete source;
}

extern AUD_API float AUD_Source_getAzimuth(AUD_Source* source)
{
	assert(source);

	return (*source)->getAzimuth();
}

extern AUD_API float AUD_Source_getElevation(AUD_Source* source)
{
	assert(source);

	return (*source)->getElevation();
}

extern AUD_API float AUD_Source_getDistance(AUD_Source* source)
{
	assert(source);

	return (*source)->getDistance();
}

extern AUD_API void AUD_Source_setAzimuth(AUD_Source* source, float azimuth)
{
	assert(source);

	(*source)->setAzimuth(azimuth);
}

extern AUD_API void AUD_Source_setElevation(AUD_Source* source, float elevation)
{
	assert(source);

	(*source)->setElevation(elevation);
}

extern AUD_API void AUD_Source_setDistance(AUD_Source* source, float distance)
{
	assert(source);

	(*source)->setDistance(distance);
}<commit_msg>Fixed undeclared variable<commit_after>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

#include "Exception.h"

#include <cassert>

using namespace aud;

#define AUD_CAPI_IMPLEMENTATION
#include "AUD_Convolution.h"

extern AUD_API AUD_HRTF* AUD_HRTF_create()
{
	try
	{
		return new AUD_HRTF(new HRTF());
	}
	catch(Exception&)
	{
		return nullptr;
	}
}

extern AUD_API void AUD_HRTF_free(AUD_HRTF* hrtfs)
{
	assert(hrtfs);
	delete hrtfs;
}

extern AUD_API void AUD_HRTF_addImpulseResponse(AUD_HRTF* hrtfs, AUD_Sound* sound, float azimuth, float elevation)
{
	assert(hrtfs);
	assert(sound);

	(*hrtfs)->addImpulseResponse(std::make_shared<StreamBuffer>(*sound), azimuth, elevation);
}

extern AUD_API AUD_Source* AUD_Source_create(float azimuth, float elevation, float distance)
{
	try
	{
		return new AUD_Source(new Source(azimuth, elevation, distance));
	}
	catch(Exception&)
	{
		return nullptr;
	}
}

extern AUD_API void AUD_Source_free(AUD_Source* source)
{
	assert(source);
	delete source;
}

extern AUD_API float AUD_Source_getAzimuth(AUD_Source* source)
{
	assert(source);

	return (*source)->getAzimuth();
}

extern AUD_API float AUD_Source_getElevation(AUD_Source* source)
{
	assert(source);

	return (*source)->getElevation();
}

extern AUD_API float AUD_Source_getDistance(AUD_Source* source)
{
	assert(source);

	return (*source)->getDistance();
}

extern AUD_API void AUD_Source_setAzimuth(AUD_Source* source, float azimuth)
{
	assert(source);

	(*source)->setAzimuth(azimuth);
}

extern AUD_API void AUD_Source_setElevation(AUD_Source* source, float elevation)
{
	assert(source);

	(*source)->setElevation(elevation);
}

extern AUD_API void AUD_Source_setDistance(AUD_Source* source, float distance)
{
	assert(source);

	(*source)->setDistance(distance);
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: BarChartType.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 13:16:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "BarChartType.hxx"

using namespace ::com::sun::star;

namespace chart
{

BarChartType::BarChartType( sal_Int32 nDim /* = 2 */ ) :
        ChartType( nDim )
{}

BarChartType::~BarChartType()
{}

// ____ XChartType ____
::rtl::OUString SAL_CALL BarChartType::getChartType()
    throw (uno::RuntimeException)
{
    return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.BarChart" ));
}

} //  namespace chart
<commit_msg>INTEGRATION: CWS chart2mst3 (1.2.4); FILE MERGED 2006/10/18 17:13:02 bm 1.2.4.7: RESYNC: (1.3-1.4); FILE MERGED 2005/10/07 12:01:07 bm 1.2.4.6: RESYNC: (1.2-1.3); FILE MERGED 2005/04/11 10:02:12 iha 1.2.4.5: defines for servicenames for charttypes (fixed apply to 2nd axis again) 2005/03/30 16:31:11 bm 1.2.4.4: make model cloneable (+first undo implementation) 2004/09/16 14:42:44 bm 1.2.4.3: API simplification 2004/09/16 12:27:25 bm 1.2.4.2: API simplification 2004/04/01 10:53:07 bm 1.2.4.1: XChartType: may return a coordinate system now<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: BarChartType.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2007-05-22 18:44:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "BarChartType.hxx"
#include "macros.hxx"
#include "servicenames_charttypes.hxx"

using namespace ::com::sun::star;

namespace chart
{

BarChartType::BarChartType(
    const uno::Reference< uno::XComponentContext > & xContext ) :
        ChartType( xContext )
{}

BarChartType::BarChartType( const BarChartType & rOther ) :
        ChartType( rOther )
{
}

BarChartType::~BarChartType()
{}

// ____ XCloneable ____
uno::Reference< util::XCloneable > SAL_CALL BarChartType::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new BarChartType( *this ));
}

// ____ XChartType ____
::rtl::OUString SAL_CALL BarChartType::getChartType()
    throw (uno::RuntimeException)
{
    return CHART2_SERVICE_NAME_CHARTTYPE_BAR;
}

uno::Sequence< ::rtl::OUString > BarChartType::getSupportedServiceNames_Static()
{
    uno::Sequence< ::rtl::OUString > aServices( 2 );
    aServices[ 0 ] = CHART2_SERVICE_NAME_CHARTTYPE_BAR;
    aServices[ 1 ] = C2U( "com.sun.star.chart2.ChartType" );
    return aServices;
}

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( BarChartType,
                             C2U( "com.sun.star.comp.chart.BarChartType" ));

} //  namespace chart
<|endoftext|>


<commit_before>#include "xchainer/context.h"

#include <cstdlib>
#include <future>

#include <gtest/gtest.h>
#include <nonstd/optional.hpp>

#include "xchainer/backend.h"
#include "xchainer/device.h"
#include "xchainer/native/native_backend.h"
#include "xchainer/native/native_device.h"
#include "xchainer/testing/threading.h"

namespace xchainer {
namespace {

TEST(ContextTest, Ctor) {
    Context();  // no throw
}

TEST(ContextTest, GetBackend) {
    Context ctx;
    Backend& backend = ctx.GetBackend("native");
    EXPECT_EQ(&backend, &ctx.GetBackend("native"));
}

TEST(ContextTest, NativeBackend) {
    Context ctx;
    native::NativeBackend& backend = ctx.GetNativeBackend();
    EXPECT_EQ(&ctx.GetBackend("native"), &backend);
}

TEST(ContextTest, GetBackendThreadSafe) {
    static constexpr size_t kRepeat = 100;
    static constexpr size_t kThreadCount = 128;

    xchainer::testing::CheckThreadSafety(
            kRepeat,
            kThreadCount,
            [](size_t /*repeat*/) { return std::make_unique<Context>(); },
            [](size_t /*thread_index*/, const std::unique_ptr<Context>& ctx) {
                Backend& backend = ctx->GetBackend("native");
                return &backend;
            },
            [this](const std::vector<Backend*>& results) {
                for (Backend* backend : results) {
                    ASSERT_EQ("native", backend->GetName());
                    ASSERT_EQ(backend, results.front());
                }
            });
}

TEST(ContextTest, BackendNotFound) {
    Context ctx;
    EXPECT_THROW(ctx.GetBackend("something_that_does_not_exist"), BackendError);
}

TEST(ContextTest, GetDevice) {
    Context ctx;
    Device& device = ctx.GetDevice({"native", 0});
    EXPECT_EQ(&device, &ctx.GetDevice({"native:0"}));
}

TEST(ContextTest, GetDeviceThreadSafe) {
    static constexpr size_t kRepeat = 100;
    static constexpr int kDeviceCount = 4;
    static constexpr size_t kThreadCountPerDevice = 32;
    static constexpr size_t kThreadCount = kDeviceCount * kThreadCountPerDevice;

    xchainer::testing::CheckThreadSafety(
            kRepeat,
            kThreadCount,
            [](size_t /*repeat*/) { return std::make_unique<Context>(); },
            [](size_t thread_index, const std::unique_ptr<Context>& ctx) {
                int device_index = thread_index / kThreadCountPerDevice;
                Device& device = ctx->GetDevice({"native", device_index});
                return &device;
            },
            [this](const std::vector<Device*>& results) {
                // Check device pointers are identical within each set of threads corresponding to one device
                for (int device_index = 0; device_index < kDeviceCount; ++device_index) {
                    auto it_first = std::next(results.begin(), device_index * kThreadCountPerDevice);
                    auto it_last = std::next(results.begin(), (device_index + 1) * kThreadCountPerDevice);
                    Device* ref_device = *it_first;

                    // Check the device index
                    ASSERT_EQ(device_index, ref_device->index());

                    for (auto it = it_first; it != it_last; ++it) {
                        ASSERT_EQ(ref_device, *it);
                    }
                }
            });
}

TEST(ContextTest, DefaultContext) {
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(nullptr);
    ASSERT_THROW(GetDefaultContext(), XchainerError);

    Context ctx;
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(&ctx);
    ASSERT_EQ(&ctx, &GetDefaultContext());

    Context global_ctx;
    SetGlobalDefaultContext(&global_ctx);
    SetDefaultContext(nullptr);
    ASSERT_EQ(&global_ctx, &GetDefaultContext());

    SetGlobalDefaultContext(&global_ctx);
    SetDefaultContext(&ctx);
    ASSERT_EQ(&ctx, &GetDefaultContext());
}

TEST(ContextTest, GlobalDefaultContext) {
    SetGlobalDefaultContext(nullptr);
    ASSERT_THROW(GetGlobalDefaultContext(), XchainerError);

    Context ctx;
    SetGlobalDefaultContext(&ctx);
    ASSERT_EQ(&ctx, &GetGlobalDefaultContext());
}

TEST(ContextTest, ThreadLocal) {
    Context ctx;
    SetDefaultContext(&ctx);

    Context ctx2;
    auto future = std::async(std::launch::async, [&ctx2] {
        SetDefaultContext(&ctx2);
        return &GetDefaultContext();
    });
    ASSERT_NE(&GetDefaultContext(), future.get());
}

TEST(ContextTest, ContextScopeCtor) {
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(nullptr);
    Context ctx1;
    {
        // ContextScope should work even if default context is not set
        ContextScope scope(ctx1);
        EXPECT_EQ(&ctx1, &GetDefaultContext());
    }
    ASSERT_THROW(GetDefaultContext(), XchainerError);
    SetDefaultContext(&ctx1);
    {
        Context ctx2;
        ContextScope scope(ctx2);
        EXPECT_EQ(&ctx2, &GetDefaultContext());
    }
    ASSERT_EQ(&ctx1, &GetDefaultContext());
    {
        ContextScope scope;
        EXPECT_EQ(&ctx1, &GetDefaultContext());
        Context ctx2;
        SetDefaultContext(&ctx2);
    }
    ASSERT_EQ(&ctx1, &GetDefaultContext());
    Context ctx2;
    {
        ContextScope scope(ctx2);
        scope.Exit();
        EXPECT_EQ(&ctx1, &GetDefaultContext());
        SetDefaultContext(&ctx2);
        // not recovered here because the scope has already existed
    }
    ASSERT_EQ(&ctx2, &GetDefaultContext());
}

TEST(ContextTest, ContextScopeResetDevice) {
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(nullptr);
    Context ctx1;
    Context ctx2;
    {
        ContextScope ctx_scope1{ctx1};
        Device& device1 = ctx1.GetDevice({"native", 0});
        DeviceScope dev_scope1{device1};

        {
            ContextScope ctx_scope2{ctx2};
            ASSERT_NE(&device1, &GetDefaultDevice());
            Device& device2 = ctx2.GetDevice({"native", 0});
            SetDefaultDevice(&device2);
        }

        EXPECT_EQ(&device1, &GetDefaultDevice());
    }
}

TEST(ContextTest, UserDefinedBackend) {
    ::setenv("XCHAINER_PATH", XCHAINER_TEST_DIR "/context_testdata", 1);
    Context ctx;
    Backend& backend0 = ctx.GetBackend("backend0");
    EXPECT_EQ("backend0", backend0.GetName());
    Backend& backend0_2 = ctx.GetBackend("backend0");
    EXPECT_EQ(&backend0, &backend0_2);
    Backend& backend1 = ctx.GetBackend("backend1");
    EXPECT_EQ("backend1", backend1.GetName());

    Device& device0 = ctx.GetDevice(std::string("backend0:0"));
    EXPECT_EQ(&backend0, &device0.backend());
}

TEST(ContextTest, GetBackendOnDefaultContext) {
    // xchainer::GetBackend
    Context ctx;
    SetDefaultContext(&ctx);
    Backend& backend = GetBackend("native");
    EXPECT_EQ(&ctx, &backend.context());
    EXPECT_EQ("native", backend.GetName());
}

TEST(ContextTest, GetNativeBackendOnDefaultContext) {
    // xchainer::GetNativeBackend
    Context ctx;
    SetDefaultContext(&ctx);
    native::NativeBackend& backend = GetNativeBackend();
    EXPECT_EQ(&ctx.GetNativeBackend(), &backend);
}

TEST(ContextTest, GetDeviceOnDefaultContext) {
    // xchainer::GetDevice
    Context ctx;
    SetDefaultContext(&ctx);
    Device& device = GetDevice({"native:0"});
    EXPECT_EQ(&ctx, &device.backend().context());
    EXPECT_EQ("native:0", device.name());
}

}  // namespace
}  // namespace xchainer
<commit_msg>Minor fixes<commit_after>#include "xchainer/context.h"

#include <cstdlib>
#include <future>

#include <gtest/gtest.h>
#include <nonstd/optional.hpp>

#include "xchainer/backend.h"
#include "xchainer/device.h"
#include "xchainer/native/native_backend.h"
#include "xchainer/native/native_device.h"
#include "xchainer/testing/threading.h"

namespace xchainer {
namespace {

TEST(ContextTest, Ctor) {
    Context();  // no throw
}

TEST(ContextTest, GetBackend) {
    Context ctx;
    Backend& backend = ctx.GetBackend("native");
    EXPECT_EQ(&backend, &ctx.GetBackend("native"));
}

TEST(ContextTest, NativeBackend) {
    Context ctx;
    native::NativeBackend& backend = ctx.GetNativeBackend();
    EXPECT_EQ(&ctx.GetBackend("native"), &backend);
}

TEST(ContextTest, GetBackendThreadSafe) {
    static constexpr size_t kRepeat = 100;
    static constexpr size_t kThreadCount = 128;
    std::string backend_name{"native"};

    xchainer::testing::CheckThreadSafety(
            kRepeat,
            kThreadCount,
            [](size_t /*repeat*/) { return std::make_unique<Context>(); },
            [&backend_name](size_t /*thread_index*/, const std::unique_ptr<Context>& ctx) {
                Backend& backend = ctx->GetBackend(backend_name);
                return &backend;
            },
            [&backend_name](const std::vector<Backend*>& results) {
                for (Backend* backend : results) {
                    ASSERT_EQ(backend, results.front());
                    ASSERT_EQ(backend_name, backend->GetName());
                }
            });
}

TEST(ContextTest, BackendNotFound) {
    Context ctx;
    EXPECT_THROW(ctx.GetBackend("something_that_does_not_exist"), BackendError);
}

TEST(ContextTest, GetDevice) {
    Context ctx;
    Device& device = ctx.GetDevice({"native", 0});
    EXPECT_EQ(&device, &ctx.GetDevice({"native:0"}));
}

TEST(ContextTest, GetDeviceThreadSafe) {
    static constexpr size_t kRepeat = 100;
    static constexpr int kDeviceCount = 4;
    static constexpr size_t kThreadCountPerDevice = 32;
    static constexpr size_t kThreadCount = kDeviceCount * kThreadCountPerDevice;

    xchainer::testing::CheckThreadSafety(
            kRepeat,
            kThreadCount,
            [](size_t /*repeat*/) { return std::make_unique<Context>(); },
            [](size_t thread_index, const std::unique_ptr<Context>& ctx) {
                int device_index = thread_index / kThreadCountPerDevice;
                Device& device = ctx->GetDevice({"native", device_index});
                return &device;
            },
            [](const std::vector<Device*>& results) {
                // Check device pointers are identical within each set of threads corresponding to one device
                for (int device_index = 0; device_index < kDeviceCount; ++device_index) {
                    auto it_first = std::next(results.begin(), device_index * kThreadCountPerDevice);
                    auto it_last = std::next(results.begin(), (device_index + 1) * kThreadCountPerDevice);
                    Device* ref_device = *it_first;

                    // Check the device index
                    ASSERT_EQ(device_index, ref_device->index());

                    for (auto it = it_first; it != it_last; ++it) {
                        ASSERT_EQ(ref_device, *it);
                    }
                }
            });
}

TEST(ContextTest, DefaultContext) {
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(nullptr);
    ASSERT_THROW(GetDefaultContext(), XchainerError);

    Context ctx;
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(&ctx);
    ASSERT_EQ(&ctx, &GetDefaultContext());

    Context global_ctx;
    SetGlobalDefaultContext(&global_ctx);
    SetDefaultContext(nullptr);
    ASSERT_EQ(&global_ctx, &GetDefaultContext());

    SetGlobalDefaultContext(&global_ctx);
    SetDefaultContext(&ctx);
    ASSERT_EQ(&ctx, &GetDefaultContext());
}

TEST(ContextTest, GlobalDefaultContext) {
    SetGlobalDefaultContext(nullptr);
    ASSERT_THROW(GetGlobalDefaultContext(), XchainerError);

    Context ctx;
    SetGlobalDefaultContext(&ctx);
    ASSERT_EQ(&ctx, &GetGlobalDefaultContext());
}

TEST(ContextTest, ThreadLocal) {
    Context ctx;
    SetDefaultContext(&ctx);

    Context ctx2;
    auto future = std::async(std::launch::async, [&ctx2] {
        SetDefaultContext(&ctx2);
        return &GetDefaultContext();
    });
    ASSERT_NE(&GetDefaultContext(), future.get());
}

TEST(ContextTest, ContextScopeCtor) {
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(nullptr);
    Context ctx1;
    {
        // ContextScope should work even if default context is not set
        ContextScope scope(ctx1);
        EXPECT_EQ(&ctx1, &GetDefaultContext());
    }
    ASSERT_THROW(GetDefaultContext(), XchainerError);
    SetDefaultContext(&ctx1);
    {
        Context ctx2;
        ContextScope scope(ctx2);
        EXPECT_EQ(&ctx2, &GetDefaultContext());
    }
    ASSERT_EQ(&ctx1, &GetDefaultContext());
    {
        ContextScope scope;
        EXPECT_EQ(&ctx1, &GetDefaultContext());
        Context ctx2;
        SetDefaultContext(&ctx2);
    }
    ASSERT_EQ(&ctx1, &GetDefaultContext());
    Context ctx2;
    {
        ContextScope scope(ctx2);
        scope.Exit();
        EXPECT_EQ(&ctx1, &GetDefaultContext());
        SetDefaultContext(&ctx2);
        // not recovered here because the scope has already existed
    }
    ASSERT_EQ(&ctx2, &GetDefaultContext());
}

TEST(ContextTest, ContextScopeResetDevice) {
    SetGlobalDefaultContext(nullptr);
    SetDefaultContext(nullptr);
    Context ctx1;
    Context ctx2;
    {
        ContextScope ctx_scope1{ctx1};
        Device& device1 = ctx1.GetDevice({"native", 0});
        DeviceScope dev_scope1{device1};

        {
            ContextScope ctx_scope2{ctx2};
            ASSERT_NE(&device1, &GetDefaultDevice());
            Device& device2 = ctx2.GetDevice({"native", 0});
            SetDefaultDevice(&device2);
        }

        EXPECT_EQ(&device1, &GetDefaultDevice());
    }
}

TEST(ContextTest, UserDefinedBackend) {
    ::setenv("XCHAINER_PATH", XCHAINER_TEST_DIR "/context_testdata", 1);
    Context ctx;
    Backend& backend0 = ctx.GetBackend("backend0");
    EXPECT_EQ("backend0", backend0.GetName());
    Backend& backend0_2 = ctx.GetBackend("backend0");
    EXPECT_EQ(&backend0, &backend0_2);
    Backend& backend1 = ctx.GetBackend("backend1");
    EXPECT_EQ("backend1", backend1.GetName());

    Device& device0 = ctx.GetDevice(std::string("backend0:0"));
    EXPECT_EQ(&backend0, &device0.backend());
}

TEST(ContextTest, GetBackendOnDefaultContext) {
    // xchainer::GetBackend
    Context ctx;
    SetDefaultContext(&ctx);
    Backend& backend = GetBackend("native");
    EXPECT_EQ(&ctx, &backend.context());
    EXPECT_EQ("native", backend.GetName());
}

TEST(ContextTest, GetNativeBackendOnDefaultContext) {
    // xchainer::GetNativeBackend
    Context ctx;
    SetDefaultContext(&ctx);
    native::NativeBackend& backend = GetNativeBackend();
    EXPECT_EQ(&ctx.GetNativeBackend(), &backend);
}

TEST(ContextTest, GetDeviceOnDefaultContext) {
    // xchainer::GetDevice
    Context ctx;
    SetDefaultContext(&ctx);
    Device& device = GetDevice({"native:0"});
    EXPECT_EQ(&ctx, &device.backend().context());
    EXPECT_EQ("native:0", device.name());
}

}  // namespace
}  // namespace xchainer
<|endoftext|>


<commit_before>#include "visnet.h"
#include "packet.h"

namespace visNET{
	Packet::Packet()
	{
		m_nSize = 0;
		m_pData = nullptr;

		m_nCursor = 0;
		m_eState = PS_WRITABLE;

		writeUInt(0); // First 4 bytes are reserved for the packets size
	}

	Packet::~Packet()
	{
		if (m_pData)
			delete[] m_pData;
	}

	void Packet::_write(const uint8_t* pData, uint32_t nLength)
	{
		if (!isState(PS_WRITABLE))
			return;

		if (!m_pData)
			m_pData = new uint8_t[nLength];
		else
			m_pData = (uint8_t*)realloc(m_pData, m_nSize + nLength);

		memcpy(m_pData + m_nSize, pData, nLength);
		m_nSize += nLength;
	}

	void Packet::writeString(const char* str)
	{
		if (!isState(PS_WRITABLE))
			return;

		uint32_t nLen = strlen(str);

		writeUInt(nLen);
		write(str, nLen);
	}

	bool Packet::_read(uint8_t* pBuffer, uint32_t nSize)
	{
		if (!isState(PS_READABLE))
			return false;

		if (!m_pData || m_nCursor + nSize > m_nSize) // Can't read without data or outside bounds
		{
			setState(PS_INVALID);
			return false;
		}

		memcpy(pBuffer, m_pData + m_nCursor, nSize);

		m_nCursor += nSize;

		return true;
	}

	bool Packet::readSkip(uint32_t nOffset)
	{
		if (!isState(PS_READABLE))
			return false;

		if (!m_pData || m_nCursor + nOffset > m_nSize) // Can't read without data or outside of bounds
		{
			setState(PS_INVALID);
			return false;
		}

		m_nCursor += nOffset;

		return true;
	}

	std::string Packet::readString()
	{
		uint32_t nLen = readUInt();
		if (!isState(PS_READABLE))
			return "";

		uint8_t* pBuffer = new uint8_t[nLen + 1]; //Add space for string terminator
		if (!read(pBuffer, nLen))
			return "";

		pBuffer[nLen] = 0;

		std::string result(reinterpret_cast<char*>(pBuffer));

		delete[] pBuffer;

		return result;
	}

	int32_t Packet::_onReceive(uint8_t* pData, uint32_t nLength)
	{
		// Can't read into an already filled packet, except if its in receive state
		if (!isState(PS_WRITABLE) && !isState(PS_INRECEIVE))
			return -1;

		if (isState(PS_WRITABLE))
		{
			delete[] m_pData;
			m_pData = new uint8_t[sizeof(m_nSize)];
			m_nSize = 0;

			setState(PS_INRECEIVE);
		}

		// If we haven't retrieved the packetsize yet
		uint32_t nRead = 0;
		if (m_nSize == 0)
		{
			// Only copy enough to get the full packet size
			uint32_t nDiff = sizeof(m_nSize) - m_nCursor;
			nRead = nLength > nDiff ? nDiff : nLength;

			memcpy(m_pData + m_nCursor, pData, nRead);
			m_nCursor += nRead;
			nLength -= nRead;

			if (m_nCursor < sizeof(m_nSize)) // Haven't received all size bytes yet
				return 0;
			else
			{
				memcpy(&m_nSize, m_pData, sizeof(m_nSize)); // Get real size
				if (m_nSize > _visNET_PACKETSIZE_LIMIT || m_nSize < sizeof(m_nSize))
				{
					setState(PS_INVALID);
					return -1;
				}

				m_pData = (uint8_t*)realloc(m_pData, m_nSize);
			}
		}

		uint32_t nAdditionalData = 0;

		// Only copy when we actually have data to write
		if (nLength != 0)
		{
			// Do not read more than required, cut off!
			if (nLength + m_nCursor <= m_nSize)
			{
				memcpy(m_pData + m_nCursor, pData + nRead, nLength);
				m_nCursor += nLength;
			}
			else
			{
				nAdditionalData = (nLength + m_nCursor) - m_nSize;
				memcpy(m_pData + m_nCursor, pData + nRead, m_nSize - m_nCursor);
				m_nCursor = m_nSize;
			}
		}

		if (m_nSize == m_nCursor)
		{
			m_nCursor = sizeof(m_nSize); // Set the cursor back for reading (0 + 4)
			setState(PS_READABLE);
		}

		return nAdditionalData; // 0 if no additionals
	}

	bool Packet::_onSend()
	{
		if (!isWritable())
			return false;

		memcpy(m_pData, &m_nSize, sizeof(m_nSize)); // Overwrite first 4 bytes

		return true;
	}

	std::shared_ptr<Packet> Packet::_copy()
	{
		if (!isWritable())
			return nullptr;

		std::shared_ptr<Packet> copy = std::make_shared<Packet>();
		// Delete initial 4 bytes
		if (copy->m_pData)
		{
			delete[] copy->m_pData;
			copy->m_pData = nullptr;
			copy->m_nSize = 0;
		}
		copy->write(m_pData, m_nSize);

		return copy;
	}
}<commit_msg>Set packetstate to invalid when trying to write outside the predefined packetlimit<commit_after>#include "visnet.h"
#include "packet.h"

namespace visNET{
	Packet::Packet()
	{
		m_nSize = 0;
		m_pData = nullptr;

		m_nCursor = 0;
		m_eState = PS_WRITABLE;

		writeUInt(0); // First 4 bytes are reserved for the packets size
	}

	Packet::~Packet()
	{
		if (m_pData)
			delete[] m_pData;
	}

	void Packet::_write(const uint8_t* pData, uint32_t nLength)
	{
		if (!isState(PS_WRITABLE))
			return;

		if (!m_pData)
			m_pData = new uint8_t[nLength];
		else
			m_pData = (uint8_t*)realloc(m_pData, m_nSize + nLength);

		memcpy(m_pData + m_nSize, pData, nLength);
		m_nSize += nLength;

		if (m_nSize > _visNET_PACKETSIZE_LIMIT)
			setState(PS_INVALID);
	}

	void Packet::writeString(const char* str)
	{
		if (!isState(PS_WRITABLE))
			return;

		uint32_t nLen = strlen(str);

		writeUInt(nLen);
		write(str, nLen);
	}

	bool Packet::_read(uint8_t* pBuffer, uint32_t nSize)
	{
		if (!isState(PS_READABLE))
			return false;

		if (!m_pData || m_nCursor + nSize > m_nSize) // Can't read without data or outside bounds
		{
			setState(PS_INVALID);
			return false;
		}

		memcpy(pBuffer, m_pData + m_nCursor, nSize);

		m_nCursor += nSize;

		return true;
	}

	bool Packet::readSkip(uint32_t nOffset)
	{
		if (!isState(PS_READABLE))
			return false;

		if (!m_pData || m_nCursor + nOffset > m_nSize) // Can't read without data or outside of bounds
		{
			setState(PS_INVALID);
			return false;
		}

		m_nCursor += nOffset;

		return true;
	}

	std::string Packet::readString()
	{
		uint32_t nLen = readUInt();
		if (!isState(PS_READABLE))
			return "";

		uint8_t* pBuffer = new uint8_t[nLen + 1]; //Add space for string terminator
		if (!read(pBuffer, nLen))
			return "";

		pBuffer[nLen] = 0;

		std::string result(reinterpret_cast<char*>(pBuffer));

		delete[] pBuffer;

		return result;
	}

	int32_t Packet::_onReceive(uint8_t* pData, uint32_t nLength)
	{
		// Can't read into an already filled packet, except if its in receive state
		if (!isState(PS_WRITABLE) && !isState(PS_INRECEIVE))
			return -1;

		if (isState(PS_WRITABLE))
		{
			delete[] m_pData;
			m_pData = new uint8_t[sizeof(m_nSize)];
			m_nSize = 0;

			setState(PS_INRECEIVE);
		}

		// If we haven't retrieved the packetsize yet
		uint32_t nRead = 0;
		if (m_nSize == 0)
		{
			// Only copy enough to get the full packet size
			uint32_t nDiff = sizeof(m_nSize) - m_nCursor;
			nRead = nLength > nDiff ? nDiff : nLength;

			memcpy(m_pData + m_nCursor, pData, nRead);
			m_nCursor += nRead;
			nLength -= nRead;

			if (m_nCursor < sizeof(m_nSize)) // Haven't received all size bytes yet
				return 0;
			else
			{
				memcpy(&m_nSize, m_pData, sizeof(m_nSize)); // Get real size
				if (m_nSize > _visNET_PACKETSIZE_LIMIT || m_nSize < sizeof(m_nSize))
				{
					setState(PS_INVALID);
					return -1;
				}

				m_pData = (uint8_t*)realloc(m_pData, m_nSize);
			}
		}

		uint32_t nAdditionalData = 0;

		// Only copy when we actually have data to write
		if (nLength != 0)
		{
			// Do not read more than required, cut off!
			if (nLength + m_nCursor <= m_nSize)
			{
				memcpy(m_pData + m_nCursor, pData + nRead, nLength);
				m_nCursor += nLength;
			}
			else
			{
				nAdditionalData = (nLength + m_nCursor) - m_nSize;
				memcpy(m_pData + m_nCursor, pData + nRead, m_nSize - m_nCursor);
				m_nCursor = m_nSize;
			}
		}

		if (m_nSize == m_nCursor)
		{
			m_nCursor = sizeof(m_nSize); // Set the cursor back for reading (0 + 4)
			setState(PS_READABLE);
		}

		return nAdditionalData; // 0 if no additionals
	}

	bool Packet::_onSend()
	{
		if (!isWritable())
			return false;

		memcpy(m_pData, &m_nSize, sizeof(m_nSize)); // Overwrite first 4 bytes

		return true;
	}

	std::shared_ptr<Packet> Packet::_copy()
	{
		if (!isWritable())
			return nullptr;

		std::shared_ptr<Packet> copy = std::make_shared<Packet>();
		// Delete initial 4 bytes
		if (copy->m_pData)
		{
			delete[] copy->m_pData;
			copy->m_pData = nullptr;
			copy->m_nSize = 0;
		}
		copy->write(m_pData, m_nSize);

		return copy;
	}
}<|endoftext|>