<commit_before>#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <fstream>
#ifdef _MSC_VER
	#pragma warning(disable : 4996) // scanf
	#define snprintf _snprintf_s
#endif

class Brainfuck : public Xbyak::CodeGenerator {
private:
	enum Direction { B, F };
	std::string toStr(int labelNo, Direction dir)
	{
		return Xbyak::Label::toStr(labelNo) + (dir == B ? 'B' : 'F');
	}
public:
	int getContinuousChar(std::istream& is, char c)
	{
		int count = 1;
		char p;
		while (is >> p) {
			if (p != c) break;
			count++;
		}
		is.unget();
		return count;
	}
	Brainfuck(std::istream& is) : CodeGenerator(100000)
	{
		// void (*)(void* putchar, void* getchar, int *stack)
		using namespace Xbyak;
#ifdef XBYAK32
		const Reg32& pPutchar(esi);
		const Reg32& pGetchar(edi);
		const Reg32& stack(ebp);
		const Address cur = dword [stack];
		push(ebp); // stack
		push(esi);
		push(edi);
		const int P_ = 4 * 3;
		mov(pPutchar, ptr[esp + P_ + 4]); // putchar
		mov(pGetchar, ptr[esp + P_ + 8]); // getchar
		mov(stack, ptr[esp + P_ + 12]); // stack
#elif defined(XBYAK64_WIN)
		const Reg64& pPutchar(rsi);
		const Reg64& pGetchar(rdi);
		const Reg64& stack(rbp); // stack
		const Address cur = dword [stack];
		push(rsi);
		push(rdi);
		push(rbp);
		mov(pPutchar, rcx); // putchar
		mov(pGetchar, rdx); // getchar
		mov(stack, r8); // stack
#else
		const Reg64& pPutchar(rbx);
		const Reg64& pGetchar(rbp);
		const Reg64& stack(r12); // stack
		const Address cur = dword [stack];
		push(rbx);
		push(rbp);
		push(r12);
		mov(pPutchar, rdi); // putchar
		mov(pGetchar, rsi); // getchar
		mov(stack, rdx); // stack
#endif
		int labelNo = 0;
		std::stack<int> keepLabelNo;
		char c;
		while (is >> c) {
			switch (c) {
			case '+':
			case '-':
				{
					int count = getContinuousChar(is, c);
					if (count == 1) {
						c == '+' ? inc(cur) : dec(cur);
					} else {
						add(cur, (c == '+' ? count : -count));
					}
				}
				break;
			case '>':
			case '<':
				{
					int count = getContinuousChar(is, c);
					add(stack, 4 * (c == '>' ? count : -count));
				}
				break;
			case '.':
#ifdef XBYAK32
				push(cur);
				call(pPutchar);
				pop(eax);
#elif defined(XBYAK64_WIN)
				mov(ecx, cur);
				sub(rsp, 32);
				call(pPutchar);
				add(rsp, 32);
#else
				mov(edi, cur);
				call(pPutchar);
#endif
				break;
			case ',':
#if defined(XBYAK32) || defined(XBYAK64_GCC)
				call(pGetchar);
#elif defined(XBYAK64_WIN)
				sub(rsp, 32);
				call(pGetchar);
				add(rsp, 32);
#endif
				mov(cur, eax);
				break;
			case '[':
				L(toStr(labelNo, B));
				mov(eax, cur);
				test(eax, eax);
				jz(toStr(labelNo, F), T_NEAR);
				keepLabelNo.push(labelNo++);
				break;
			case ']':
				{
					int no = keepLabelNo.top(); keepLabelNo.pop();
					jmp(toStr(no, B));
					L(toStr(no, F));
				}
				break;
			default:
				break;
			}
		}
#ifdef XBYAK32
		pop(edi);
		pop(esi);
		pop(ebp);
#elif defined(XBYAK64_WIN)
		pop(rbp);
		pop(rdi);
		pop(rsi);
#else
		pop(r12);
		pop(rbp);
		pop(rbx);
#endif
		ret();
	}
};

void dump(const Xbyak::uint8 *code, size_t size)
{
	puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
#ifdef _MSC_VER
	printf("static __declspec(align(4096)) ");
#else
	printf("static __attribute__((aligned(4096)))");
#endif
	puts("const unsigned char code[] = {");
	for (size_t i = 0; i < size; i++) {
		printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
	}
	puts("\n};");
#ifdef _MSC_VER
	puts("#include <windows.h>");
#else
	puts("#include <unistd.h>");
	puts("#include <sys/mman.h>");
#endif
	puts("int main()\n{");
#ifdef _MSC_VER
	puts("\tDWORD oldProtect;");
	puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
#else
	puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
	puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
#endif
	puts(
		"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
		"}"
	);
}

int main(int argc, char *argv[])
{
#ifdef XBYAK32
	fprintf(stderr, "32bit mode\n");
#else
	fprintf(stderr, "64bit mode\n");
#endif
	if (argc == 1) {
		fprintf(stderr, "bf filename.bf [0|1]\n");
		return 1;
	}
	std::ifstream ifs(argv[1]);
	int mode = argc == 3 ? atoi(argv[2]) : 0;
	try {
		Brainfuck bf(ifs);
		if (mode == 0) {
			static int stack[128 * 1024];
			bf.getCode<void (*)(void*, void*, int *)>()(Xbyak::CastTo<void*>(putchar), Xbyak::CastTo<void*>(getchar), stack);
		} else {
			dump(bf.getCode(), bf.getSize());
		}
	} catch (std::exception& e) {
		printf("ERR:%s\n", e.what());
	} catch (...) {
		printf("unknown error\n");
	}
}

<commit_msg>bf uses Label class<commit_after>#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <fstream>
#ifdef _MSC_VER
	#pragma warning(disable : 4996) // scanf
	#define snprintf _snprintf_s
#endif

class Brainfuck : public Xbyak::CodeGenerator {
public:
	int getContinuousChar(std::istream& is, char c)
	{
		int count = 1;
		char p;
		while (is >> p) {
			if (p != c) break;
			count++;
		}
		is.unget();
		return count;
	}
	Brainfuck(std::istream& is) : CodeGenerator(100000)
	{
		// void (*)(void* putchar, void* getchar, int *stack)
		using namespace Xbyak;
#ifdef XBYAK32
		const Reg32& pPutchar(esi);
		const Reg32& pGetchar(edi);
		const Reg32& stack(ebp);
		const Address cur = dword [stack];
		push(ebp); // stack
		push(esi);
		push(edi);
		const int P_ = 4 * 3;
		mov(pPutchar, ptr[esp + P_ + 4]); // putchar
		mov(pGetchar, ptr[esp + P_ + 8]); // getchar
		mov(stack, ptr[esp + P_ + 12]); // stack
#elif defined(XBYAK64_WIN)
		const Reg64& pPutchar(rsi);
		const Reg64& pGetchar(rdi);
		const Reg64& stack(rbp); // stack
		const Address cur = dword [stack];
		push(rsi);
		push(rdi);
		push(rbp);
		mov(pPutchar, rcx); // putchar
		mov(pGetchar, rdx); // getchar
		mov(stack, r8); // stack
#else
		const Reg64& pPutchar(rbx);
		const Reg64& pGetchar(rbp);
		const Reg64& stack(r12); // stack
		const Address cur = dword [stack];
		push(rbx);
		push(rbp);
		push(r12);
		mov(pPutchar, rdi); // putchar
		mov(pGetchar, rsi); // getchar
		mov(stack, rdx); // stack
#endif
		std::stack<Label> labelF, labelB;
		char c;
		while (is >> c) {
			switch (c) {
			case '+':
			case '-':
				{
					int count = getContinuousChar(is, c);
					if (count == 1) {
						c == '+' ? inc(cur) : dec(cur);
					} else {
						add(cur, (c == '+' ? count : -count));
					}
				}
				break;
			case '>':
			case '<':
				{
					int count = getContinuousChar(is, c);
					add(stack, 4 * (c == '>' ? count : -count));
				}
				break;
			case '.':
#ifdef XBYAK32
				push(cur);
				call(pPutchar);
				pop(eax);
#elif defined(XBYAK64_WIN)
				mov(ecx, cur);
				sub(rsp, 32);
				call(pPutchar);
				add(rsp, 32);
#else
				mov(edi, cur);
				call(pPutchar);
#endif
				break;
			case ',':
#if defined(XBYAK32) || defined(XBYAK64_GCC)
				call(pGetchar);
#elif defined(XBYAK64_WIN)
				sub(rsp, 32);
				call(pGetchar);
				add(rsp, 32);
#endif
				mov(cur, eax);
				break;
			case '[':
				{
					Label B = L();
					labelB.push(B);
					mov(eax, cur);
					test(eax, eax);
					Label F;
					jz(F, T_NEAR);
					labelF.push(F);
				}
				break;
			case ']':
				{
					Label B = labelB.top(); labelB.pop();
					jmp(B);
					Label F = labelF.top(); labelF.pop();
					L(F);
				}
				break;
			default:
				break;
			}
		}
#ifdef XBYAK32
		pop(edi);
		pop(esi);
		pop(ebp);
#elif defined(XBYAK64_WIN)
		pop(rbp);
		pop(rdi);
		pop(rsi);
#else
		pop(r12);
		pop(rbp);
		pop(rbx);
#endif
		ret();
	}
};

void dump(const Xbyak::uint8 *code, size_t size)
{
	puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
#ifdef _MSC_VER
	printf("static __declspec(align(4096)) ");
#else
	printf("static __attribute__((aligned(4096)))");
#endif
	puts("const unsigned char code[] = {");
	for (size_t i = 0; i < size; i++) {
		printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
	}
	puts("\n};");
#ifdef _MSC_VER
	puts("#include <windows.h>");
#else
	puts("#include <unistd.h>");
	puts("#include <sys/mman.h>");
#endif
	puts("int main()\n{");
#ifdef _MSC_VER
	puts("\tDWORD oldProtect;");
	puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
#else
	puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
	puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
#endif
	puts(
		"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
		"}"
	);
}

int main(int argc, char *argv[])
{
#ifdef XBYAK32
	fprintf(stderr, "32bit mode\n");
#else
	fprintf(stderr, "64bit mode\n");
#endif
	if (argc == 1) {
		fprintf(stderr, "bf filename.bf [0|1]\n");
		return 1;
	}
	std::ifstream ifs(argv[1]);
	int mode = argc == 3 ? atoi(argv[2]) : 0;
	try {
		Brainfuck bf(ifs);
		if (mode == 0) {
			static int stack[128 * 1024];
			bf.getCode<void (*)(void*, void*, int *)>()(Xbyak::CastTo<void*>(putchar), Xbyak::CastTo<void*>(getchar), stack);
		} else {
			dump(bf.getCode(), bf.getSize());
		}
	} catch (std::exception& e) {
		printf("ERR:%s\n", e.what());
	} catch (...) {
		printf("unknown error\n");
	}
}

<|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Cards/Cards.h>

#include <better-enums/enum.h>
#include <clara.hpp>

#ifdef HEARTHSTONEPP_WINDOWS
#include <filesystem>
#endif
#ifdef HEARTHSTONEPP_LINUX
#include <experimental/filesystem>
#endif
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
#include <vector>

using namespace Hearthstonepp;

#ifndef HEARTHSTONEPP_MACOSX
namespace filesystem = std::experimental::filesystem;
#endif

inline std::string ToString(const clara::Opt& opt)
{
    std::ostringstream oss;
    oss << (clara::Parser() | opt);
    return oss.str();
}

inline std::string ToString(const clara::Parser& p)
{
    std::ostringstream oss;
    oss << p;
    return oss.str();
}

inline std::vector<GameTag> CheckAbilityImpl(const std::string& path)
{
    std::map<std::string, GameTag> abilityStrMap = {
        { "Adapt", GameTag::ADAPT },
        { "Charge", GameTag::CHARGE },
        { "DivineShield", GameTag::DIVINE_SHIELD },
        { "Freeze", GameTag::FREEZE },
        { "Poisonous", GameTag::POISONOUS },
        { "Stealth", GameTag::STEALTH },
        { "Taunt", GameTag::TAUNT },
        { "Windfury", GameTag::WINDFURY }
    };

    std::vector<GameTag> result;

#ifndef HEARTHSTONEPP_MACOSX
    const filesystem::path p(
        path + "/Tests/UnitTests/Tasks/BasicTasks/CombatTaskTests.cpp");

    if (!filesystem::exists(p))
    {
        std::cerr << p << " does not exist\n";
        exit(EXIT_FAILURE);
    }

    if (!filesystem::is_regular_file(p))
    {
        std::cerr << p << " exists, but is not regular file\n";
        exit(EXIT_FAILURE);
    }

    std::ifstream abilityFile;
    abilityFile.open(p.string());

    if (!abilityFile.is_open())
    {
        std::cerr << p << " couldn't open\n";
        exit(EXIT_FAILURE);
    }

    std::string line;
    while (std::getline(abilityFile, line))
    {
        for (auto& ability : abilityStrMap)
        {
            std::string sentence = "TEST(CombatTask, " + ability.first + ")";
            if (line.find(sentence, 0) != std::string::npos)
            {
                result.emplace_back(ability.second);
                break;
            }
        }
    }

#else
    std::cerr
        << "CheckAbilityImpl skip: apple-clang doesn't support <filesystem>\n";
    exit(EXIT_FAILURE);
#endif

    return result;
}

inline std::vector<Card> QueryCardSetList(const std::string& projectPath,
                                          CardSet cardSet, bool implCardOnly)
{
    // Excludes this cards because it has power that doesn't appear in ability
    // EX1_508: Grimscale Oracle (CORE)
    // CS2_146: Southsea Deckhand (EXPERT1)
    // DS1_188: Gladiator's Longbow (EXPERT1)
    // EX1_105: Mountain Giant (EXPERT1)
    // EX1_335: Lightspawn (EXPERT1)
    // EX1_350: Prophet Velen (EXPERT1)
    // EX1_411: Gorehowl (EXPERT1)
    // EX1_560: Nozdormu (EXPERT1)
    // EX1_586: Sea Giant (EXPERT1)
    // NEW1_022: Dread Corsair (EXPERT1)
    std::vector<std::string> excludeCardList = {
        "EX1_508", "CS2_146", "DS1_188", "EX1_105", "EX1_335",
        "EX1_350", "EX1_411", "EX1_560", "EX1_586", "NEW1_022",
    };

    if (cardSet == +CardSet::ALL)
    {
        return Cards::GetInstance()->GetAllCards();
    }

    std::vector<GameTag> abilityList{};
    if (implCardOnly)
    {
        abilityList = CheckAbilityImpl(projectPath);
    }

    std::vector<Card> result;
    for (auto& card : Cards::GetInstance()->FindCardBySet(cardSet))
    {
        if (implCardOnly)
        {
            bool isAbilityImpl = true;
            for (auto& mechanic : card.mechanics)
            {
                if (std::find(abilityList.begin(), abilityList.end(),
                              mechanic) == abilityList.end())
                {
                    isAbilityImpl = false;
                    break;
                }
            }

            // Counts minion and weapon card only
            if (isAbilityImpl && (card.cardType == +CardType::MINION ||
                                  card.cardType == +CardType::WEAPON))
            {
                result.emplace_back(card);
            }
        }
        else
        {
            result.emplace_back(card);
        }
    }

    return result;
}

inline bool CheckCardImpl(const std::string& path, std::vector<Card>& cards,
                          const std::string& id)
{
#ifndef HEARTHSTONEPP_MACOSX
    auto iter = std::find_if(cards.begin(), cards.end(),
                             [&id](const Card& c) { return c.id == id; });
    if (iter != cards.end())
    {
        return true;
    }

    const filesystem::path p(path + "/Tests/UnitTests/CardSets");

    if (!filesystem::exists(p))
    {
        std::cerr << p << " does not exist\n";
        exit(EXIT_FAILURE);
    }

    if (!filesystem::is_directory(p))
    {
        std::cerr << p << " exists, but is not directory\n";
        exit(EXIT_FAILURE);
    }

    for (auto&& file : filesystem::recursive_directory_iterator(p))
    {
        std::regex fileNamePattern(R"(.*\\(.*)\..*$)");
        std::smatch match;

        std::string pathStr = file.path().string();

        if (std::regex_match(pathStr, match, fileNamePattern))
        {
            if (match[1] == id)
            {
                return true;
            }
        }
    }
#else
    std::cerr
        << "CheckCardImpl skip: apple-clang doesn't support <filesystem>\n";
    exit(EXIT_FAILURE);
#endif

    return false;
}

inline void ExportFile(const std::string& projectPath, CardSet cardSet,
                       std::vector<Card>& cards)
{
    std::ofstream outputFile("result.md");
    if (outputFile)
    {
        auto cardsInCardSet = Cards::GetInstance()->FindCardBySet(cardSet);

        // Excludes cards that is not collectible
        cardsInCardSet.erase(
            std::remove_if(cardsInCardSet.begin(), cardsInCardSet.end(),
                           [](const Card& c) { return !c.isCollectible; }),
            cardsInCardSet.end());

        // Excludes 9 hero cards from CardSet::CORE
        if (cardSet == +CardSet::CORE)
        {
            cardsInCardSet.erase(
                std::remove_if(cardsInCardSet.begin(), cardsInCardSet.end(),
                               [](const Card& c) {
                                   return c.cardType == +CardType::HERO;
                               }),
                cardsInCardSet.end());
        }

        size_t impledCardNum = 0;
        const size_t allCardNum = cardsInCardSet.size();

        outputFile << "Set | ID | Name | Implemented\n";
        outputFile << ":---: | :---: | :---: | :---:\n";

        for (auto& card : cardsInCardSet)
        {
            std::string mechanicStr;
            for (auto& mechanic : card.mechanics)
            {
                mechanicStr += mechanic._to_string();
            }

            const bool isImplemented =
                CheckCardImpl(projectPath, cards, card.id);
            if (isImplemented)
            {
                impledCardNum++;
            }

            outputFile << card.cardSet._to_string() << " | " << card.id << " | "
                       << card.name << " | " << (isImplemented ? 'O' : ' ')
                       << '\n';
        }

        // Adds the number of card that implemented by ability
        const size_t implPercent = static_cast<size_t>(
            static_cast<double>(impledCardNum) / allCardNum * 100);
        outputFile << '\n';
        outputFile << "- Progress: " << implPercent << "% (" << impledCardNum
                   << " of " << allCardNum << " Cards)";

        std::cout << "Export file is completed.\n";
        exit(EXIT_SUCCESS);
    }

    std::cerr << "Failed to write file result.md\n";
    exit(EXIT_FAILURE);
}

int main(int argc, char* argv[])
{
    // Parse command
    bool showHelp = false;
    bool isExportAllCard = false;
    bool implCardOnly = false;
    std::string cardSetName;
    std::string projectPath;

    // Parsing
    auto parser = clara::Help(showHelp) |
                  clara::Opt(isExportAllCard)["-a"]["--all"](
                      "Export a list of all expansion cards") |
                  clara::Opt(cardSetName, "cardSet")["-c"]["--cardset"](
                      "Export a list of specific expansion cards") |
                  clara::Opt(implCardOnly)["-i"]["--implcardonly"](
                      "Export a list of cards that need to be implemented") |
                  clara::Opt(projectPath, "path")["-p"]["--path"](
                      "Specify Hearthstone++ project path");

    auto result = parser.parse(clara::Args(argc, argv));
    if (!result)
    {
        std::cerr << "Error in command line: " << result.errorMessage() << '\n';
        exit(EXIT_FAILURE);
    }

    if (showHelp)
    {
        std::cout << ToString(parser) << '\n';
        exit(EXIT_SUCCESS);
    }

    if (projectPath.empty())
    {
        std::cout << "You should input Hearthstone++ project path\n";
        exit(EXIT_FAILURE);
    }

    CardSet cardSet = CardSet::INVALID;

    if (isExportAllCard)
    {
        cardSet = CardSet::ALL;
    }
    else if (!cardSetName.empty())
    {
        const auto convertedCardSet =
            CardSet::_from_string_nothrow(cardSetName.c_str());
        if (!convertedCardSet)
        {
            std::cerr << "Invalid card set name: " << cardSetName << '\n';
            exit(EXIT_FAILURE);
        }

        cardSet = *convertedCardSet;
    }

    std::vector<Card> cards =
        QueryCardSetList(projectPath, cardSet, implCardOnly);

    if (cards.empty())
    {
        std::cerr << "Your search did not generate any hits.\n";
        exit(EXIT_SUCCESS);
    }

    ExportFile(projectPath, cardSet, cards);

    exit(EXIT_SUCCESS);
}<commit_msg>feat(improve-tool): Excludes cards that power doesn't appear in ability<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Cards/Cards.h>

#include <better-enums/enum.h>
#include <clara.hpp>

#ifdef HEARTHSTONEPP_WINDOWS
#include <filesystem>
#endif
#ifdef HEARTHSTONEPP_LINUX
#include <experimental/filesystem>
#endif
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
#include <vector>

using namespace Hearthstonepp;

#ifndef HEARTHSTONEPP_MACOSX
namespace filesystem = std::experimental::filesystem;
#endif

inline std::string ToString(const clara::Opt& opt)
{
    std::ostringstream oss;
    oss << (clara::Parser() | opt);
    return oss.str();
}

inline std::string ToString(const clara::Parser& p)
{
    std::ostringstream oss;
    oss << p;
    return oss.str();
}

inline std::vector<GameTag> CheckAbilityImpl(const std::string& path)
{
    std::map<std::string, GameTag> abilityStrMap = {
        { "Adapt", GameTag::ADAPT },
        { "Charge", GameTag::CHARGE },
        { "DivineShield", GameTag::DIVINE_SHIELD },
        { "Freeze", GameTag::FREEZE },
        { "Poisonous", GameTag::POISONOUS },
        { "Stealth", GameTag::STEALTH },
        { "Taunt", GameTag::TAUNT },
        { "Windfury", GameTag::WINDFURY }
    };

    std::vector<GameTag> result;

#ifndef HEARTHSTONEPP_MACOSX
    const filesystem::path p(
        path + "/Tests/UnitTests/Tasks/BasicTasks/CombatTaskTests.cpp");

    if (!filesystem::exists(p))
    {
        std::cerr << p << " does not exist\n";
        exit(EXIT_FAILURE);
    }

    if (!filesystem::is_regular_file(p))
    {
        std::cerr << p << " exists, but is not regular file\n";
        exit(EXIT_FAILURE);
    }

    std::ifstream abilityFile;
    abilityFile.open(p.string());

    if (!abilityFile.is_open())
    {
        std::cerr << p << " couldn't open\n";
        exit(EXIT_FAILURE);
    }

    std::string line;
    while (std::getline(abilityFile, line))
    {
        for (auto& ability : abilityStrMap)
        {
            std::string sentence = "TEST(CombatTask, " + ability.first + ")";
            if (line.find(sentence, 0) != std::string::npos)
            {
                result.emplace_back(ability.second);
                break;
            }
        }
    }

#else
    std::cerr
        << "CheckAbilityImpl skip: apple-clang doesn't support <filesystem>\n";
    exit(EXIT_FAILURE);
#endif

    return result;
}

inline std::vector<Card> QueryCardSetList(const std::string& projectPath,
                                          CardSet cardSet, bool implCardOnly)
{
    // Excludes this cards because it has power that doesn't appear in ability
    // EX1_508: Grimscale Oracle (CORE)
    // CS2_146: Southsea Deckhand (EXPERT1)
    // DS1_188: Gladiator's Longbow (EXPERT1)
    // EX1_105: Mountain Giant (EXPERT1)
    // EX1_335: Lightspawn (EXPERT1)
    // EX1_350: Prophet Velen (EXPERT1)
    // EX1_411: Gorehowl (EXPERT1)
    // EX1_560: Nozdormu (EXPERT1)
    // EX1_586: Sea Giant (EXPERT1)
    // NEW1_022: Dread Corsair (EXPERT1)
    std::vector<std::string> excludeCardList = {
        "EX1_508", "CS2_146", "DS1_188", "EX1_105", "EX1_335",
        "EX1_350", "EX1_411", "EX1_560", "EX1_586", "NEW1_022",
    };

    if (cardSet == +CardSet::ALL)
    {
        return Cards::GetInstance()->GetAllCards();
    }

    std::vector<GameTag> abilityList{};
    if (implCardOnly)
    {
        abilityList = CheckAbilityImpl(projectPath);
    }

    std::vector<Card> result;
    for (auto& card : Cards::GetInstance()->FindCardBySet(cardSet))
    {
        if (implCardOnly)
        {
            // Excludes cards that its power doesn't appear in ability
            if (std::find(excludeCardList.begin(), excludeCardList.end(),
                          card.id) != excludeCardList.end())
            {
                continue;
            }

            bool isAbilityImpl = true;
            for (auto& mechanic : card.mechanics)
            {
                if (std::find(abilityList.begin(), abilityList.end(),
                              mechanic) == abilityList.end())
                {
                    isAbilityImpl = false;
                    break;
                }
            }

            // Counts minion and weapon card only
            if (isAbilityImpl && (card.cardType == +CardType::MINION ||
                                  card.cardType == +CardType::WEAPON))
            {
                result.emplace_back(card);
            }
        }
        else
        {
            result.emplace_back(card);
        }
    }

    return result;
}

inline bool CheckCardImpl(const std::string& path, std::vector<Card>& cards,
                          const std::string& id)
{
#ifndef HEARTHSTONEPP_MACOSX
    auto iter = std::find_if(cards.begin(), cards.end(),
                             [&id](const Card& c) { return c.id == id; });
    if (iter != cards.end())
    {
        return true;
    }

    const filesystem::path p(path + "/Tests/UnitTests/CardSets");

    if (!filesystem::exists(p))
    {
        std::cerr << p << " does not exist\n";
        exit(EXIT_FAILURE);
    }

    if (!filesystem::is_directory(p))
    {
        std::cerr << p << " exists, but is not directory\n";
        exit(EXIT_FAILURE);
    }

    for (auto&& file : filesystem::recursive_directory_iterator(p))
    {
        std::regex fileNamePattern(R"(.*\\(.*)\..*$)");
        std::smatch match;

        std::string pathStr = file.path().string();

        if (std::regex_match(pathStr, match, fileNamePattern))
        {
            if (match[1] == id)
            {
                return true;
            }
        }
    }
#else
    std::cerr
        << "CheckCardImpl skip: apple-clang doesn't support <filesystem>\n";
    exit(EXIT_FAILURE);
#endif

    return false;
}

inline void ExportFile(const std::string& projectPath, CardSet cardSet,
                       std::vector<Card>& cards)
{
    std::ofstream outputFile("result.md");
    if (outputFile)
    {
        auto cardsInCardSet = Cards::GetInstance()->FindCardBySet(cardSet);

        // Excludes cards that is not collectible
        cardsInCardSet.erase(
            std::remove_if(cardsInCardSet.begin(), cardsInCardSet.end(),
                           [](const Card& c) { return !c.isCollectible; }),
            cardsInCardSet.end());

        // Excludes 9 hero cards from CardSet::CORE
        if (cardSet == +CardSet::CORE)
        {
            cardsInCardSet.erase(
                std::remove_if(cardsInCardSet.begin(), cardsInCardSet.end(),
                               [](const Card& c) {
                                   return c.cardType == +CardType::HERO;
                               }),
                cardsInCardSet.end());
        }

        size_t impledCardNum = 0;
        const size_t allCardNum = cardsInCardSet.size();

        outputFile << "Set | ID | Name | Implemented\n";
        outputFile << ":---: | :---: | :---: | :---:\n";

        for (auto& card : cardsInCardSet)
        {
            std::string mechanicStr;
            for (auto& mechanic : card.mechanics)
            {
                mechanicStr += mechanic._to_string();
            }

            const bool isImplemented =
                CheckCardImpl(projectPath, cards, card.id);
            if (isImplemented)
            {
                impledCardNum++;
            }

            outputFile << card.cardSet._to_string() << " | " << card.id << " | "
                       << card.name << " | " << (isImplemented ? 'O' : ' ')
                       << '\n';
        }

        // Adds the number of card that implemented by ability
        const size_t implPercent = static_cast<size_t>(
            static_cast<double>(impledCardNum) / allCardNum * 100);
        outputFile << '\n';
        outputFile << "- Progress: " << implPercent << "% (" << impledCardNum
                   << " of " << allCardNum << " Cards)";

        std::cout << "Export file is completed.\n";
        exit(EXIT_SUCCESS);
    }

    std::cerr << "Failed to write file result.md\n";
    exit(EXIT_FAILURE);
}

int main(int argc, char* argv[])
{
    // Parse command
    bool showHelp = false;
    bool isExportAllCard = false;
    bool implCardOnly = false;
    std::string cardSetName;
    std::string projectPath;

    // Parsing
    auto parser = clara::Help(showHelp) |
                  clara::Opt(isExportAllCard)["-a"]["--all"](
                      "Export a list of all expansion cards") |
                  clara::Opt(cardSetName, "cardSet")["-c"]["--cardset"](
                      "Export a list of specific expansion cards") |
                  clara::Opt(implCardOnly)["-i"]["--implcardonly"](
                      "Export a list of cards that need to be implemented") |
                  clara::Opt(projectPath, "path")["-p"]["--path"](
                      "Specify Hearthstone++ project path");

    auto result = parser.parse(clara::Args(argc, argv));
    if (!result)
    {
        std::cerr << "Error in command line: " << result.errorMessage() << '\n';
        exit(EXIT_FAILURE);
    }

    if (showHelp)
    {
        std::cout << ToString(parser) << '\n';
        exit(EXIT_SUCCESS);
    }

    if (projectPath.empty())
    {
        std::cout << "You should input Hearthstone++ project path\n";
        exit(EXIT_FAILURE);
    }

    CardSet cardSet = CardSet::INVALID;

    if (isExportAllCard)
    {
        cardSet = CardSet::ALL;
    }
    else if (!cardSetName.empty())
    {
        const auto convertedCardSet =
            CardSet::_from_string_nothrow(cardSetName.c_str());
        if (!convertedCardSet)
        {
            std::cerr << "Invalid card set name: " << cardSetName << '\n';
            exit(EXIT_FAILURE);
        }

        cardSet = *convertedCardSet;
    }

    std::vector<Card> cards =
        QueryCardSetList(projectPath, cardSet, implCardOnly);

    if (cards.empty())
    {
        std::cerr << "Your search did not generate any hits.\n";
        exit(EXIT_SUCCESS);
    }

    ExportFile(projectPath, cardSet, cards);

    exit(EXIT_SUCCESS);
}<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
// --- ROOT system ---
#include <iostream>
#include <TClonesArray.h>
#include <TFile.h>
#include <TH1F.h>
#include <TH1I.h>

// --- AliRoot header files ---
#include "AliESDEvent.h"
#include "AliLog.h"
#include "AliFMDQADataMakerRec.h"
#include "AliFMDDigit.h"
#include "AliFMDRecPoint.h"
#include "AliQAChecker.h"
#include "AliESDFMD.h"
#include "AliFMDParameters.h"
#include "AliFMDRawReader.h"
#include "AliRawReader.h"
#include "AliFMDAltroMapping.h"

//_____________________________________________________________________
// This is the class that collects the QA data for the FMD during
// reconstruction.
//
// The following data types are picked up:
// - rec points
// - esd data
// - raws
// Author : Hans Hjersing Dalsgaard, hans.dalsgaard@cern.ch
//_____________________________________________________________________

ClassImp(AliFMDQADataMakerRec)
#if 0
; // For Emacs - do not delete!
#endif

//_____________________________________________________________________
AliFMDQADataMakerRec::AliFMDQADataMakerRec() :
  AliQADataMakerRec(AliQAv1::GetDetName(AliQAv1::kFMD),
		    "FMD Quality Assurance Data Maker"),
  fRecPointsArray("AliFMDRecPoint", 1000)
{
  // ctor

}

//_____________________________________________________________________
AliFMDQADataMakerRec::AliFMDQADataMakerRec(const AliFMDQADataMakerRec& qadm)
  : AliQADataMakerRec(AliQAv1::GetDetName(AliQAv1::kFMD),
		      "FMD Quality Assurance Data Maker"),
    fRecPointsArray(qadm.fRecPointsArray)
{
  // copy ctor
  // Parameters:
  //    qadm    Object to copy from

}
//_____________________________________________________________________
AliFMDQADataMakerRec& AliFMDQADataMakerRec::operator = (const AliFMDQADataMakerRec& qadm )
{
  fRecPointsArray = qadm.fRecPointsArray;

  return *this;
}
//_____________________________________________________________________
AliFMDQADataMakerRec::~AliFMDQADataMakerRec()
{

}

//_____________________________________________________________________

void
AliFMDQADataMakerRec::EndOfDetectorCycle(AliQAv1::TASKINDEX_t task,
					 TObjArray ** list)
{
  // Detector specific actions at end of cycle
  // do the QA checking
  AliLog::Message(5,"FMD: end of detector cycle",
		  "AliFMDQADataMakerRec","AliFMDQADataMakerRec",
		  "AliFMDQADataMakerRec::EndOfDetectorCycle",
		  "AliFMDQADataMakerRec.cxx",95);
  AliQAChecker::Instance()->Run(AliQAv1::kFMD, task, list);
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitESDs()
{
  // create Digits histograms in Digits subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1F* hEnergyOfESD = new TH1F("hEnergyOfESD","Energy distribution",100,0,3);
  hEnergyOfESD->SetXTitle("Edep/Emip");
  hEnergyOfESD->SetYTitle("Counts");
  Add2ESDsList(hEnergyOfESD, 0, !expert, image);

}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitDigits()
{
  // create Digits histograms in Digits subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1I* hADCCounts = new TH1I("hADCCounts","Dist of ADC counts;ADC counts;Counts",1024,0,1024);
  Add2DigitsList(hADCCounts, 0, !expert, image);
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitRecPoints()
{
  // create Reconstructed Points histograms in RecPoints subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1F* hEnergyOfRecpoints = new TH1F("hEnergyOfRecpoints",
				      "Energy Distribution",100,0,3);
  hEnergyOfRecpoints->SetXTitle("Edep/Emip");
  hEnergyOfRecpoints->SetYTitle("Counts");
  Add2RecPointsList(hEnergyOfRecpoints,0, !expert, image);
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitRaws()
{
  // create Raws histograms in Raws subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t saveCorr = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1I* hADCCounts;
  for(Int_t det = 1; det<=3; det++) {
    Int_t firstring = (det==1 ? 1 : 0);
    for(Int_t iring = firstring;iring<=1;iring++) {
      Char_t ring = (iring == 1 ? 'I' : 'O');
      hADCCounts      = new TH1I(Form("hADCCounts_FMD%d%c",
				      det, ring), "ADC counts;Amplitude [ADC counts];Counts",
				 1024,0,1023);

      Int_t index1 = GetHalfringIndex(det, ring, 0,1);
      Add2RawsList(hADCCounts, index1, expert, !image, !saveCorr);

      for(Int_t b = 0; b<=1;b++) {

	//Hexadecimal board numbers 0x0, 0x1, 0x10, 0x11;
	UInt_t board = (iring == 1 ? 0 : 1);
	board = board + b*16;

	hADCCounts      = new TH1I(Form("hADCCounts_FMD%d%c_board%d",
					det, ring, board), "ADC counts;Amplitude [ADC counts];Counts",
				   1024,0,1023);
	hADCCounts->SetXTitle("ADC counts");
	hADCCounts->SetYTitle("");
	Int_t index2 = GetHalfringIndex(det, ring, board/16,0);
	Add2RawsList(hADCCounts, index2, !expert, image, !saveCorr);

      }
    }
  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeESDs(AliESDEvent * esd)
{
  if(!esd) {
    AliError("FMD ESD object not found!!") ;
    return;
  }
  AliESDFMD* fmd = esd->GetFMDData();
  if (!fmd) return;

  for(UShort_t det=1;det<=3;det++) {
    for (UShort_t ir = 0; ir < 2; ir++) {
      Char_t   ring = (ir == 0 ? 'I' : 'O');
      UShort_t nsec = (ir == 0 ? 20  : 40);
      UShort_t nstr = (ir == 0 ? 512 : 256);
      for(UShort_t sec =0; sec < nsec;  sec++)  {
	for(UShort_t strip = 0; strip < nstr; strip++) {
	  Float_t mult = fmd->Multiplicity(det,ring,sec,strip);
	  if(mult == AliESDFMD::kInvalidMult) continue;

	  GetESDsData(0)->Fill(mult);
	}
      }
    }
  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeDigits()
{
  // makes data from Digits
  if(!fDigitsArray)  {
    AliError("FMD Digit object not found!!") ;
    return;
  }

  for(Int_t i=0;i<fDigitsArray->GetEntriesFast();i++) {
    //Raw ADC counts
    AliFMDDigit* digit = static_cast<AliFMDDigit*>(fDigitsArray->At(i));
    GetDigitsData(0)->Fill(digit->Counts());
  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeDigits(TTree * digitTree)
{

  if (fDigitsArray)
    fDigitsArray->Clear();
  else
    fDigitsArray = new TClonesArray("AliFMDDigit", 1000);

  TBranch*      branch = digitTree->GetBranch("FMD");
  if (!branch) {
    AliWarning("FMD branch in Digit Tree not found") ;
    return;
  }
  branch->SetAddress(&fDigitsArray);
  branch->GetEntry(0);
  MakeDigits();
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeRaws(AliRawReader* rawReader)
{

 AliFMDRawReader fmdReader(rawReader,0);

  if (fDigitsArray)
    fDigitsArray->Clear();
  else
    fDigitsArray = new TClonesArray("AliFMDDigit", 1000);

  TClonesArray* digitsAddress = fDigitsArray;

  rawReader->Reset();

  digitsAddress->Clear();
  fmdReader.ReadAdcs(digitsAddress);
  for(Int_t i=0;i<digitsAddress->GetEntriesFast();i++) {
    //Raw ADC counts
    AliFMDDigit*      digit = static_cast<AliFMDDigit*>(digitsAddress->At(i));
    UShort_t          det   = digit->Detector();
    Char_t            ring  = digit->Ring();
    UShort_t          sec   = digit->Sector();
    // UShort_t strip = digit->Strip();
    AliFMDParameters* pars  = AliFMDParameters::Instance();
    Short_t           board = pars->GetAltroMap()->Sector2Board(ring, sec);

    Int_t index1 = GetHalfringIndex(det, ring, 0, 1);
    GetRawsData(index1)->Fill(digit->Counts());
    Int_t index2 = GetHalfringIndex(det, ring, board/16,0);
    GetRawsData(index2)->Fill(digit->Counts());

  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeRecPoints(TTree* clustersTree)
{
  // makes data from RecPoints

   AliFMDParameters* pars = AliFMDParameters::Instance();
  fRecPointsArray.Clear();
  TBranch *fmdbranch = clustersTree->GetBranch("FMD");
  if (!fmdbranch) {
    AliError("can't get the branch with the FMD recpoints !");
    return;
  }

  TClonesArray* RecPointsAddress = &fRecPointsArray;

  fmdbranch->SetAddress(&RecPointsAddress);
  fmdbranch->GetEntry(0);
  TIter next(RecPointsAddress) ;
  AliFMDRecPoint * rp ;
  while ((rp = static_cast<AliFMDRecPoint*>(next()))) {

    GetRecPointsData(0)->Fill(rp->Edep()/pars->GetEdepMip()) ;

  }

}

//_____________________________________________________________________
void AliFMDQADataMakerRec::StartOfDetectorCycle()
{
  // What
  // to
  // do?
}
//_____________________________________________________________________
Int_t AliFMDQADataMakerRec::GetHalfringIndex(UShort_t det,
					     Char_t ring,
					     UShort_t board,
					     UShort_t monitor) {

  UShort_t iring  =  (ring == 'I' ? 1 : 0);

  Int_t index = ( ((det-1) << 3) | (iring << 2) | (board << 1) | (monitor << 0));

  return index-2;

}

//_____________________________________________________________________

//
// EOF
//
<commit_msg>Fixed serious bug in QA code<commit_after>/**************************************************************************
 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
// --- ROOT system ---
#include <iostream>
#include <TClonesArray.h>
#include <TFile.h>
#include <TH1F.h>
#include <TH1I.h>

// --- AliRoot header files ---
#include "AliESDEvent.h"
#include "AliLog.h"
#include "AliFMDQADataMakerRec.h"
#include "AliFMDDigit.h"
#include "AliFMDRecPoint.h"
#include "AliQAChecker.h"
#include "AliESDFMD.h"
#include "AliFMDParameters.h"
#include "AliFMDRawReader.h"
#include "AliRawReader.h"
#include "AliFMDAltroMapping.h"
#include "AliFMDDebug.h"

//_____________________________________________________________________
// This is the class that collects the QA data for the FMD during
// reconstruction.
//
// The following data types are picked up:
// - rec points
// - esd data
// - raws
// Author : Hans Hjersing Dalsgaard, hans.dalsgaard@cern.ch
//_____________________________________________________________________

ClassImp(AliFMDQADataMakerRec)
#if 0
; // For Emacs - do not delete!
#endif

//_____________________________________________________________________
AliFMDQADataMakerRec::AliFMDQADataMakerRec() :
  AliQADataMakerRec(AliQAv1::GetDetName(AliQAv1::kFMD),
		    "FMD Quality Assurance Data Maker"),
  fRecPointsArray("AliFMDRecPoint", 1000)
{
  // ctor

}

//_____________________________________________________________________
AliFMDQADataMakerRec::AliFMDQADataMakerRec(const AliFMDQADataMakerRec& qadm)
  : AliQADataMakerRec(AliQAv1::GetDetName(AliQAv1::kFMD),
		      "FMD Quality Assurance Data Maker"),
    fRecPointsArray(qadm.fRecPointsArray)
{
  // copy ctor
  // Parameters:
  //    qadm    Object to copy from

}
//_____________________________________________________________________
AliFMDQADataMakerRec& AliFMDQADataMakerRec::operator = (const AliFMDQADataMakerRec& qadm )
{
  fRecPointsArray = qadm.fRecPointsArray;

  return *this;
}
//_____________________________________________________________________
AliFMDQADataMakerRec::~AliFMDQADataMakerRec()
{

}

//_____________________________________________________________________

void
AliFMDQADataMakerRec::EndOfDetectorCycle(AliQAv1::TASKINDEX_t task,
					 TObjArray ** list)
{
  // Detector specific actions at end of cycle
  // do the QA checking
  AliLog::Message(5,"FMD: end of detector cycle",
		  "AliFMDQADataMakerRec","AliFMDQADataMakerRec",
		  "AliFMDQADataMakerRec::EndOfDetectorCycle",
		  "AliFMDQADataMakerRec.cxx",95);
  AliQAChecker::Instance()->Run(AliQAv1::kFMD, task, list);
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitESDs()
{
  // create Digits histograms in Digits subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1F* hEnergyOfESD = new TH1F("hEnergyOfESD","Energy distribution",100,0,3);
  hEnergyOfESD->SetXTitle("Edep/Emip");
  hEnergyOfESD->SetYTitle("Counts");
  Add2ESDsList(hEnergyOfESD, 0, !expert, image);

}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitDigits()
{
  // create Digits histograms in Digits subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1I* hADCCounts = new TH1I("hADCCounts","Dist of ADC counts;ADC counts;Counts",1024,0,1024);
  Add2DigitsList(hADCCounts, 0, !expert, image);
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitRecPoints()
{
  // create Reconstructed Points histograms in RecPoints subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1F* hEnergyOfRecpoints = new TH1F("hEnergyOfRecpoints",
				      "Energy Distribution",100,0,3);
  hEnergyOfRecpoints->SetXTitle("Edep/Emip");
  hEnergyOfRecpoints->SetYTitle("Counts");
  Add2RecPointsList(hEnergyOfRecpoints,0, !expert, image);
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::InitRaws()
{
  // create Raws histograms in Raws subdir
  const Bool_t expert   = kTRUE ;
  const Bool_t saveCorr = kTRUE ;
  const Bool_t image    = kTRUE ;

  TH1I* hADCCounts;
  for(Int_t det = 1; det<=3; det++) {
    Int_t firstring = (det==1 ? 1 : 0);
    for(Int_t iring = firstring;iring<=1;iring++) {
      Char_t ring = (iring == 1 ? 'I' : 'O');
      hADCCounts      = new TH1I(Form("hADCCounts_FMD%d%c",
				      det, ring), "ADC counts;Amplitude [ADC counts];Counts",
				 1024,0,1023);

      Int_t index1 = GetHalfringIndex(det, ring, 0,1);
      Add2RawsList(hADCCounts, index1, expert, !image, !saveCorr);

      for(Int_t b = 0; b<=1;b++) {

	//Hexadecimal board numbers 0x0, 0x1, 0x10, 0x11;
	UInt_t board = (iring == 1 ? 0 : 1);
	board = board + b*16;

	hADCCounts      = new TH1I(Form("hADCCounts_FMD%d%c_board%d",
					det, ring, board), "ADC counts;Amplitude [ADC counts];Counts",
				   1024,0,1023);
	hADCCounts->SetXTitle("ADC counts");
	hADCCounts->SetYTitle("");
	Int_t index2 = GetHalfringIndex(det, ring, board/16,0);
	Add2RawsList(hADCCounts, index2, !expert, image, !saveCorr);

      }
    }
  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeESDs(AliESDEvent * esd)
{
  if(!esd) {
    AliError("FMD ESD object not found!!") ;
    return;
  }
  AliFMDDebug(2, ("Will loop over ESD data and fill histogram"));

  AliESDFMD* fmd = esd->GetFMDData();
  if (!fmd) return;

  // FIXME - we should use AliESDFMD::ForOne subclass to do this!
  for(UShort_t det=1;det<=3;det++) {
    UShort_t nrng = (det == 1 ? 1 : 2);
    for (UShort_t ir = 0; ir < nrng; ir++) {
      Char_t   ring = (ir == 0 ? 'I' : 'O');
      UShort_t nsec = (ir == 0 ? 20  : 40);
      UShort_t nstr = (ir == 0 ? 512 : 256);
      for(UShort_t sec =0; sec < nsec;  sec++)  {
	for(UShort_t strip = 0; strip < nstr; strip++) {
	  Float_t mult = fmd->Multiplicity(det,ring,sec,strip);
	  if(mult == AliESDFMD::kInvalidMult) continue;

	  GetESDsData(0)->Fill(mult);
	}
      }
    }
  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeDigits()
{
  // makes data from Digits
  if(!fDigitsArray)  {
    AliError("FMD Digit object not found!!") ;
    return;
  }

  for(Int_t i=0;i<fDigitsArray->GetEntriesFast();i++) {
    //Raw ADC counts
    AliFMDDigit* digit = static_cast<AliFMDDigit*>(fDigitsArray->At(i));
    GetDigitsData(0)->Fill(digit->Counts());
  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeDigits(TTree * digitTree)
{

  if (fDigitsArray)
    fDigitsArray->Clear();
  else
    fDigitsArray = new TClonesArray("AliFMDDigit", 1000);

  TBranch*      branch = digitTree->GetBranch("FMD");
  if (!branch) {
    AliWarning("FMD branch in Digit Tree not found") ;
    return;
  }
  branch->SetAddress(&fDigitsArray);
  branch->GetEntry(0);
  MakeDigits();
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeRaws(AliRawReader* rawReader)
{

 AliFMDRawReader fmdReader(rawReader,0);

  if (fDigitsArray)
    fDigitsArray->Clear();
  else
    fDigitsArray = new TClonesArray("AliFMDDigit", 1000);

  TClonesArray* digitsAddress = fDigitsArray;

  rawReader->Reset();

  digitsAddress->Clear();
  fmdReader.ReadAdcs(digitsAddress);
  for(Int_t i=0;i<digitsAddress->GetEntriesFast();i++) {
    //Raw ADC counts
    AliFMDDigit*      digit = static_cast<AliFMDDigit*>(digitsAddress->At(i));
    UShort_t          det   = digit->Detector();
    Char_t            ring  = digit->Ring();
    UShort_t          sec   = digit->Sector();
    // UShort_t strip = digit->Strip();
    AliFMDParameters* pars  = AliFMDParameters::Instance();
    Short_t           board = pars->GetAltroMap()->Sector2Board(ring, sec);

    Int_t index1 = GetHalfringIndex(det, ring, 0, 1);
    GetRawsData(index1)->Fill(digit->Counts());
    Int_t index2 = GetHalfringIndex(det, ring, board/16,0);
    GetRawsData(index2)->Fill(digit->Counts());

  }
}

//_____________________________________________________________________
void AliFMDQADataMakerRec::MakeRecPoints(TTree* clustersTree)
{
  // makes data from RecPoints

   AliFMDParameters* pars = AliFMDParameters::Instance();
  fRecPointsArray.Clear();
  TBranch *fmdbranch = clustersTree->GetBranch("FMD");
  if (!fmdbranch) {
    AliError("can't get the branch with the FMD recpoints !");
    return;
  }

  TClonesArray* RecPointsAddress = &fRecPointsArray;

  fmdbranch->SetAddress(&RecPointsAddress);
  fmdbranch->GetEntry(0);
  TIter next(RecPointsAddress) ;
  AliFMDRecPoint * rp ;
  while ((rp = static_cast<AliFMDRecPoint*>(next()))) {

    GetRecPointsData(0)->Fill(rp->Edep()/pars->GetEdepMip()) ;

  }

}

//_____________________________________________________________________
void AliFMDQADataMakerRec::StartOfDetectorCycle()
{
  // What
  // to
  // do?
}
//_____________________________________________________________________
Int_t AliFMDQADataMakerRec::GetHalfringIndex(UShort_t det,
					     Char_t ring,
					     UShort_t board,
					     UShort_t monitor) {

  UShort_t iring  =  (ring == 'I' ? 1 : 0);

  Int_t index = ( ((det-1) << 3) | (iring << 2) | (board << 1) | (monitor << 0));

  return index-2;

}

//_____________________________________________________________________

//
// EOF
//
<|endoftext|>


<commit_before>#ifndef EBITEN_GRAPHICS_AFFINE_MATRIX_HPP
#define EBITEN_GRAPHICS_AFFINE_MATRIX_HPP

#include <array>
#include <cassert>
#include <mutex>

namespace ebiten {
namespace graphics {

/*
 * | e00, e01, ..., e0D |
 * | e10, e11, ..., e1D |
 * |  : ,  : ,    ,  :  |
 * | eD0, eD1, ..., eDD |
 */
template<class Float, std::size_t Dimension, class Self>
class affine_matrix {
  static_assert(0 < Dimension, "Dimension must be more than 0");
#ifdef EBITEN_TEST
private:
  FRIEND_TEST(affine_matrix, element);
  FRIEND_TEST(affine_matrix, is_identity);
  FRIEND_TEST(affine_matrix, multiply);
#endif
private:
  static std::size_t const size_ = Dimension * (Dimension - 1);
  typedef std::array<Float, size_> elements_type;
  static std::once_flag identity_once_flag_;
  elements_type elements_;
protected:
  affine_matrix() {
    this->elements_.fill(0);
  }
  template<class InputIterator>
  affine_matrix(InputIterator const& begin, InputIterator const& end) {
    std::copy(begin, end, this->elements_.begin());
  }
  virtual
  ~affine_matrix() {
  }
public:
  Float
  element(std::size_t i, std::size_t j) const {
    assert(i < Dimension);
    assert(j < Dimension);
    if (i == Dimension - 1) {
      if (j == Dimension - 1) {
        return 1;
      }
      return 0;
    }
    return this->elements_[i * Dimension + j];
  }
  void
  set_element(std::size_t i, std::size_t j, Float element) {
    assert(i < Dimension - 1);
    assert(j < Dimension);
    this->elements_[i * Dimension + j] = element;
  }
  bool
  is_identity() const {
    typename elements_type::const_iterator it = this->elements_.begin();
    for (std::size_t i = 0; i < Dimension - 1; ++i) {
      for (std::size_t j = 0; j < Dimension; ++j, ++it) {
        if (i == j) {
          if (*it != 1) {
            return false;
          }
        } else {
          if (*it != 0) {
            return false;
          }
        }
      }
    }
    return true;
  }
  static Self
  identity() {
    static Self identity_;
    std::call_once(identity_once_flag_, initialize_identity, std::ref<Self>(identity_));
    return identity_;
  }
  Self
  concat(Self const& other) const {
    Self result;
    elements_type const& lhs_elements = other.elements_;
    elements_type const& rhs_elements = this->elements_;
    typename elements_type::iterator it = result.elements_.begin();
    for (std::size_t i = 0; i < Dimension - 1; ++i) {
      for (std::size_t j = 0; j < Dimension; ++j, ++it) {
        Float e = 0;
        for (std::size_t k = 0; k < Dimension - 1; ++k) {
          e += lhs_elements[i * Dimension + k] * rhs_elements[k * Dimension + j];
        }
        if (j == Dimension - 1) {
          e += lhs_elements[i * Dimension + Dimension - 1];
        }
        *it = e;
      }
    }
    return result;
  }
private:
  static void
  initialize_identity(Self& identity) {
    typename elements_type::iterator it = identity.elements_.begin();
    for (std::size_t i = 0; i < Dimension - 1; ++i) {
      for (std::size_t j = 0; j < Dimension; ++j, ++it) {
        if (i == j) {
          *it = 1;
        } else {
          *it = 0;
        }
      }
    }
  }
};

template<class Float, std::size_t Dimension, class Self>
std::once_flag affine_matrix<Float, Dimension, Self>::identity_once_flag_;

}
}

#ifdef EBITEN_TEST

namespace ebiten {
namespace graphics {

template<class Float, std::size_t Dimension>
class affine_matrix_impl : public affine_matrix<Float,
                                                Dimension,
                                                affine_matrix_impl<Float, Dimension>> {
};

TEST(affine_matrix, element) {
  affine_matrix_impl<double, 4> m;
  m.set_element(0, 0, 1);
  m.set_element(0, 1, 2);
  m.set_element(0, 2, 3);
  EXPECT_EQ(1, (m.element(0, 0)));
  EXPECT_EQ(2, (m.element(0, 1)));
  EXPECT_EQ(3, (m.element(0, 2)));
  EXPECT_EQ(0, (m.element(0, 3)));
  EXPECT_EQ(0, (m.element(1, 0)));
  EXPECT_EQ(0, (m.element(1, 1)));
  EXPECT_EQ(0, (m.element(1, 2)));
  EXPECT_EQ(0, (m.element(1, 3)));
  EXPECT_EQ(0, (m.element(2, 0)));
  EXPECT_EQ(0, (m.element(2, 1)));
  EXPECT_EQ(0, (m.element(2, 2)));
  EXPECT_EQ(0, (m.element(2, 3)));
  EXPECT_EQ(0, (m.element(3, 0)));
  EXPECT_EQ(0, (m.element(3, 1)));
  EXPECT_EQ(0, (m.element(3, 2)));
  EXPECT_EQ(1, (m.element(3, 3)));
  m.set_element(1, 0, 4);
  m.set_element(1, 1, 5);
  m.set_element(2, 3, 6);
  EXPECT_EQ(1, (m.element(0, 0)));
  EXPECT_EQ(2, (m.element(0, 1)));
  EXPECT_EQ(3, (m.element(0, 2)));
  EXPECT_EQ(0, (m.element(0, 3)));
  EXPECT_EQ(4, (m.element(1, 0)));
  EXPECT_EQ(5, (m.element(1, 1)));
  EXPECT_EQ(0, (m.element(1, 2)));
  EXPECT_EQ(0, (m.element(1, 3)));
  EXPECT_EQ(0, (m.element(2, 0)));
  EXPECT_EQ(0, (m.element(2, 1)));
  EXPECT_EQ(0, (m.element(2, 2)));
  EXPECT_EQ(6, (m.element(2, 3)));
  EXPECT_EQ(0, (m.element(3, 0)));
  EXPECT_EQ(0, (m.element(3, 1)));
  EXPECT_EQ(0, (m.element(3, 2)));
  EXPECT_EQ(1, (m.element(3, 3)));
}

TEST(affine_matrix, is_identity) {
  affine_matrix_impl<double, 4> m1;
  m1.set_element(0, 0, 1);
  m1.set_element(1, 1, 1);
  m1.set_element(2, 2, 1);
  EXPECT_TRUE(m1.is_identity());
  affine_matrix_impl<double, 4> m2 = m1;
  EXPECT_TRUE(m2.is_identity());
  m2.set_element(0, 1, 1);
  EXPECT_FALSE(m2.is_identity());
}

TEST(affine_matrix, multiply) {
  {
    affine_matrix_impl<double, 3> m1 = affine_matrix_impl<double, 3>::identity();
    affine_matrix_impl<double, 3> m2 = affine_matrix_impl<double, 3>::identity();
    m1.set_element(0, 0, 2);
    m1.set_element(1, 1, 2);
    m2.set_element(0, 2, 1);
    m2.set_element(1, 2, 1);
    {
      affine_matrix_impl<double, 3> m3 = m1.concat(m2);
      EXPECT_EQ(2, (m3.element(0, 0)));
      EXPECT_EQ(0, (m3.element(0, 1)));
      EXPECT_EQ(1, (m3.element(0, 2)));
      EXPECT_EQ(0, (m3.element(1, 0)));
      EXPECT_EQ(2, (m3.element(1, 1)));
      EXPECT_EQ(1, (m3.element(1, 2)));
      EXPECT_EQ(0, (m3.element(2, 0)));
      EXPECT_EQ(0, (m3.element(2, 1)));
      EXPECT_EQ(1, (m3.element(2, 2)));
    }
    {
      affine_matrix_impl<double, 3> m3 = m2.concat(m1);
      EXPECT_EQ(2, (m3.element(0, 0)));
      EXPECT_EQ(0, (m3.element(0, 1)));
      EXPECT_EQ(2, (m3.element(0, 2)));
      EXPECT_EQ(0, (m3.element(1, 0)));
      EXPECT_EQ(2, (m3.element(1, 1)));
      EXPECT_EQ(2, (m3.element(1, 2)));
      EXPECT_EQ(0, (m3.element(2, 0)));
      EXPECT_EQ(0, (m3.element(2, 1)));
      EXPECT_EQ(1, (m3.element(2, 2)));
    }
  }
  {
    affine_matrix_impl<double, 4> m1;
    affine_matrix_impl<double, 4> m2;
    m1.set_element(0, 0, 1);
    m1.set_element(0, 1, 2);
    m1.set_element(0, 2, 3);
    m1.set_element(0, 3, 4);
    m1.set_element(1, 0, 5);
    m1.set_element(1, 1, 6);
    m1.set_element(1, 2, 7);
    m1.set_element(1, 3, 8);
    m1.set_element(2, 0, 9);
    m1.set_element(2, 1, 10);
    m1.set_element(2, 2, 11);
    m1.set_element(2, 3, 12);
    m2.set_element(0, 0, 13);
    m2.set_element(0, 1, 14);
    m2.set_element(0, 2, 15);
    m2.set_element(0, 3, 16);
    m2.set_element(1, 0, 17);
    m2.set_element(1, 1, 18);
    m2.set_element(1, 2, 19);
    m2.set_element(1, 3, 20);
    m2.set_element(2, 0, 21);
    m2.set_element(2, 1, 22);
    m2.set_element(2, 2, 23);
    m2.set_element(2, 3, 24);
    {
      affine_matrix_impl<double, 4> m3 = m1.concat(m2);
      EXPECT_EQ(218, (m3.element(0, 0)));
      EXPECT_EQ(260, (m3.element(0, 1)));
      EXPECT_EQ(302, (m3.element(0, 2)));
      EXPECT_EQ(360, (m3.element(0, 3)));
      EXPECT_EQ(278, (m3.element(1, 0)));
      EXPECT_EQ(332, (m3.element(1, 1)));
      EXPECT_EQ(386, (m3.element(1, 2)));
      EXPECT_EQ(460, (m3.element(1, 3)));
      EXPECT_EQ(338, (m3.element(2, 0)));
      EXPECT_EQ(404, (m3.element(2, 1)));
      EXPECT_EQ(470, (m3.element(2, 2)));
      EXPECT_EQ(560, (m3.element(2, 3)));
      EXPECT_EQ(0,   (m3.element(3, 0)));
      EXPECT_EQ(0,   (m3.element(3, 1)));
      EXPECT_EQ(0,   (m3.element(3, 2)));
      EXPECT_EQ(1,   (m3.element(3, 3)));
    }
    {
      affine_matrix_impl<double, 4> m3 = m2.concat(m1);
      EXPECT_EQ(110, (m3.element(0, 0)));
      EXPECT_EQ(116, (m3.element(0, 1)));
      EXPECT_EQ(122, (m3.element(0, 2)));
      EXPECT_EQ(132, (m3.element(0, 3)));
      EXPECT_EQ(314, (m3.element(1, 0)));
      EXPECT_EQ(332, (m3.element(1, 1)));
      EXPECT_EQ(350, (m3.element(1, 2)));
      EXPECT_EQ(376, (m3.element(1, 3)));
      EXPECT_EQ(518, (m3.element(2, 0)));
      EXPECT_EQ(548, (m3.element(2, 1)));
      EXPECT_EQ(578, (m3.element(2, 2)));
      EXPECT_EQ(620, (m3.element(2, 3)));
      EXPECT_EQ(0,   (m3.element(3, 0)));
      EXPECT_EQ(0,   (m3.element(3, 1)));
      EXPECT_EQ(0,   (m3.element(3, 2)));
      EXPECT_EQ(1,   (m3.element(3, 3)));
    }
  }
}

}
}

#endif

#endif
<commit_msg>Changed the signature of affine_matrix#identity()<commit_after>#ifndef EBITEN_GRAPHICS_AFFINE_MATRIX_HPP
#define EBITEN_GRAPHICS_AFFINE_MATRIX_HPP

#include <array>
#include <cassert>
#include <mutex>

namespace ebiten {
namespace graphics {

/*
 * | e00, e01, ..., e0D |
 * | e10, e11, ..., e1D |
 * |  : ,  : ,    ,  :  |
 * | eD0, eD1, ..., eDD |
 */
template<class Float, std::size_t Dimension, class Self>
class affine_matrix {
  static_assert(0 < Dimension, "Dimension must be more than 0");
#ifdef EBITEN_TEST
private:
  FRIEND_TEST(affine_matrix, element);
  FRIEND_TEST(affine_matrix, is_identity);
  FRIEND_TEST(affine_matrix, multiply);
#endif
private:
  static std::size_t const size_ = Dimension * (Dimension - 1);
  typedef std::array<Float, size_> elements_type;
  static std::once_flag identity_once_flag_;
  elements_type elements_;
protected:
  affine_matrix() {
    this->elements_.fill(0);
  }
  template<class InputIterator>
  affine_matrix(InputIterator const& begin, InputIterator const& end) {
    std::copy(begin, end, this->elements_.begin());
  }
  virtual
  ~affine_matrix() {
  }
public:
  Float
  element(std::size_t i, std::size_t j) const {
    assert(i < Dimension);
    assert(j < Dimension);
    if (i == Dimension - 1) {
      if (j == Dimension - 1) {
        return 1;
      }
      return 0;
    }
    return this->elements_[i * Dimension + j];
  }
  void
  set_element(std::size_t i, std::size_t j, Float element) {
    assert(i < Dimension - 1);
    assert(j < Dimension);
    this->elements_[i * Dimension + j] = element;
  }
  bool
  is_identity() const {
    typename elements_type::const_iterator it = this->elements_.begin();
    for (std::size_t i = 0; i < Dimension - 1; ++i) {
      for (std::size_t j = 0; j < Dimension; ++j, ++it) {
        if (i == j) {
          if (*it != 1) {
            return false;
          }
        } else {
          if (*it != 0) {
            return false;
          }
        }
      }
    }
    return true;
  }
  static Self const&
  identity() {
    static Self identity_;
    std::call_once(identity_once_flag_, initialize_identity, std::ref<Self>(identity_));
    return identity_;
  }
  Self
  concat(Self const& other) const {
    Self result;
    elements_type const& lhs_elements = other.elements_;
    elements_type const& rhs_elements = this->elements_;
    typename elements_type::iterator it = result.elements_.begin();
    for (std::size_t i = 0; i < Dimension - 1; ++i) {
      for (std::size_t j = 0; j < Dimension; ++j, ++it) {
        Float e = 0;
        for (std::size_t k = 0; k < Dimension - 1; ++k) {
          e += lhs_elements[i * Dimension + k] * rhs_elements[k * Dimension + j];
        }
        if (j == Dimension - 1) {
          e += lhs_elements[i * Dimension + Dimension - 1];
        }
        *it = e;
      }
    }
    return result;
  }
private:
  static void
  initialize_identity(Self& identity) {
    typename elements_type::iterator it = identity.elements_.begin();
    for (std::size_t i = 0; i < Dimension - 1; ++i) {
      for (std::size_t j = 0; j < Dimension; ++j, ++it) {
        if (i == j) {
          *it = 1;
        } else {
          *it = 0;
        }
      }
    }
  }
};

template<class Float, std::size_t Dimension, class Self>
std::once_flag affine_matrix<Float, Dimension, Self>::identity_once_flag_;

}
}

#ifdef EBITEN_TEST

namespace ebiten {
namespace graphics {

template<class Float, std::size_t Dimension>
class affine_matrix_impl : public affine_matrix<Float,
                                                Dimension,
                                                affine_matrix_impl<Float, Dimension>> {
};

TEST(affine_matrix, element) {
  affine_matrix_impl<double, 4> m;
  m.set_element(0, 0, 1);
  m.set_element(0, 1, 2);
  m.set_element(0, 2, 3);
  EXPECT_EQ(1, (m.element(0, 0)));
  EXPECT_EQ(2, (m.element(0, 1)));
  EXPECT_EQ(3, (m.element(0, 2)));
  EXPECT_EQ(0, (m.element(0, 3)));
  EXPECT_EQ(0, (m.element(1, 0)));
  EXPECT_EQ(0, (m.element(1, 1)));
  EXPECT_EQ(0, (m.element(1, 2)));
  EXPECT_EQ(0, (m.element(1, 3)));
  EXPECT_EQ(0, (m.element(2, 0)));
  EXPECT_EQ(0, (m.element(2, 1)));
  EXPECT_EQ(0, (m.element(2, 2)));
  EXPECT_EQ(0, (m.element(2, 3)));
  EXPECT_EQ(0, (m.element(3, 0)));
  EXPECT_EQ(0, (m.element(3, 1)));
  EXPECT_EQ(0, (m.element(3, 2)));
  EXPECT_EQ(1, (m.element(3, 3)));
  m.set_element(1, 0, 4);
  m.set_element(1, 1, 5);
  m.set_element(2, 3, 6);
  EXPECT_EQ(1, (m.element(0, 0)));
  EXPECT_EQ(2, (m.element(0, 1)));
  EXPECT_EQ(3, (m.element(0, 2)));
  EXPECT_EQ(0, (m.element(0, 3)));
  EXPECT_EQ(4, (m.element(1, 0)));
  EXPECT_EQ(5, (m.element(1, 1)));
  EXPECT_EQ(0, (m.element(1, 2)));
  EXPECT_EQ(0, (m.element(1, 3)));
  EXPECT_EQ(0, (m.element(2, 0)));
  EXPECT_EQ(0, (m.element(2, 1)));
  EXPECT_EQ(0, (m.element(2, 2)));
  EXPECT_EQ(6, (m.element(2, 3)));
  EXPECT_EQ(0, (m.element(3, 0)));
  EXPECT_EQ(0, (m.element(3, 1)));
  EXPECT_EQ(0, (m.element(3, 2)));
  EXPECT_EQ(1, (m.element(3, 3)));
}

TEST(affine_matrix, is_identity) {
  affine_matrix_impl<double, 4> m1;
  m1.set_element(0, 0, 1);
  m1.set_element(1, 1, 1);
  m1.set_element(2, 2, 1);
  EXPECT_TRUE(m1.is_identity());
  affine_matrix_impl<double, 4> m2 = m1;
  EXPECT_TRUE(m2.is_identity());
  m2.set_element(0, 1, 1);
  EXPECT_FALSE(m2.is_identity());
}

TEST(affine_matrix, multiply) {
  {
    affine_matrix_impl<double, 3> m1 = affine_matrix_impl<double, 3>::identity();
    affine_matrix_impl<double, 3> m2 = affine_matrix_impl<double, 3>::identity();
    m1.set_element(0, 0, 2);
    m1.set_element(1, 1, 2);
    m2.set_element(0, 2, 1);
    m2.set_element(1, 2, 1);
    {
      affine_matrix_impl<double, 3> m3 = m1.concat(m2);
      EXPECT_EQ(2, (m3.element(0, 0)));
      EXPECT_EQ(0, (m3.element(0, 1)));
      EXPECT_EQ(1, (m3.element(0, 2)));
      EXPECT_EQ(0, (m3.element(1, 0)));
      EXPECT_EQ(2, (m3.element(1, 1)));
      EXPECT_EQ(1, (m3.element(1, 2)));
      EXPECT_EQ(0, (m3.element(2, 0)));
      EXPECT_EQ(0, (m3.element(2, 1)));
      EXPECT_EQ(1, (m3.element(2, 2)));
    }
    {
      affine_matrix_impl<double, 3> m3 = m2.concat(m1);
      EXPECT_EQ(2, (m3.element(0, 0)));
      EXPECT_EQ(0, (m3.element(0, 1)));
      EXPECT_EQ(2, (m3.element(0, 2)));
      EXPECT_EQ(0, (m3.element(1, 0)));
      EXPECT_EQ(2, (m3.element(1, 1)));
      EXPECT_EQ(2, (m3.element(1, 2)));
      EXPECT_EQ(0, (m3.element(2, 0)));
      EXPECT_EQ(0, (m3.element(2, 1)));
      EXPECT_EQ(1, (m3.element(2, 2)));
    }
  }
  {
    affine_matrix_impl<double, 4> m1;
    affine_matrix_impl<double, 4> m2;
    m1.set_element(0, 0, 1);
    m1.set_element(0, 1, 2);
    m1.set_element(0, 2, 3);
    m1.set_element(0, 3, 4);
    m1.set_element(1, 0, 5);
    m1.set_element(1, 1, 6);
    m1.set_element(1, 2, 7);
    m1.set_element(1, 3, 8);
    m1.set_element(2, 0, 9);
    m1.set_element(2, 1, 10);
    m1.set_element(2, 2, 11);
    m1.set_element(2, 3, 12);
    m2.set_element(0, 0, 13);
    m2.set_element(0, 1, 14);
    m2.set_element(0, 2, 15);
    m2.set_element(0, 3, 16);
    m2.set_element(1, 0, 17);
    m2.set_element(1, 1, 18);
    m2.set_element(1, 2, 19);
    m2.set_element(1, 3, 20);
    m2.set_element(2, 0, 21);
    m2.set_element(2, 1, 22);
    m2.set_element(2, 2, 23);
    m2.set_element(2, 3, 24);
    {
      affine_matrix_impl<double, 4> m3 = m1.concat(m2);
      EXPECT_EQ(218, (m3.element(0, 0)));
      EXPECT_EQ(260, (m3.element(0, 1)));
      EXPECT_EQ(302, (m3.element(0, 2)));
      EXPECT_EQ(360, (m3.element(0, 3)));
      EXPECT_EQ(278, (m3.element(1, 0)));
      EXPECT_EQ(332, (m3.element(1, 1)));
      EXPECT_EQ(386, (m3.element(1, 2)));
      EXPECT_EQ(460, (m3.element(1, 3)));
      EXPECT_EQ(338, (m3.element(2, 0)));
      EXPECT_EQ(404, (m3.element(2, 1)));
      EXPECT_EQ(470, (m3.element(2, 2)));
      EXPECT_EQ(560, (m3.element(2, 3)));
      EXPECT_EQ(0,   (m3.element(3, 0)));
      EXPECT_EQ(0,   (m3.element(3, 1)));
      EXPECT_EQ(0,   (m3.element(3, 2)));
      EXPECT_EQ(1,   (m3.element(3, 3)));
    }
    {
      affine_matrix_impl<double, 4> m3 = m2.concat(m1);
      EXPECT_EQ(110, (m3.element(0, 0)));
      EXPECT_EQ(116, (m3.element(0, 1)));
      EXPECT_EQ(122, (m3.element(0, 2)));
      EXPECT_EQ(132, (m3.element(0, 3)));
      EXPECT_EQ(314, (m3.element(1, 0)));
      EXPECT_EQ(332, (m3.element(1, 1)));
      EXPECT_EQ(350, (m3.element(1, 2)));
      EXPECT_EQ(376, (m3.element(1, 3)));
      EXPECT_EQ(518, (m3.element(2, 0)));
      EXPECT_EQ(548, (m3.element(2, 1)));
      EXPECT_EQ(578, (m3.element(2, 2)));
      EXPECT_EQ(620, (m3.element(2, 3)));
      EXPECT_EQ(0,   (m3.element(3, 0)));
      EXPECT_EQ(0,   (m3.element(3, 1)));
      EXPECT_EQ(0,   (m3.element(3, 2)));
      EXPECT_EQ(1,   (m3.element(3, 3)));
    }
  }
}

}
}

#endif

#endif
<|endoftext|>


<commit_before>/**
 * @file streamingaudio_fmodex.cpp
 * @brief LLStreamingAudio_FMODEX implementation
 *
 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "llmath.h"

#include "fmod.hpp"
#include "fmod_errors.h"

#include "llstreamingaudio_fmodex.h"

class LLAudioStreamManagerFMODEX
{
public:
	LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
	FMOD::Channel* startStream();
	bool stopStream(); // Returns true if the stream was successfully stopped.
	bool ready();

	const std::string& getURL() 	{ return mInternetStreamURL; }

	FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL);
protected:
	FMOD::System* mSystem;
	FMOD::Channel* mStreamChannel;
	FMOD::Sound* mInternetStream;
	bool mReady;

	std::string mInternetStreamURL;
};

//---------------------------------------------------------------------------
// Internet Streaming
//---------------------------------------------------------------------------
LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
	mSystem(system),
	mCurrentInternetStreamp(NULL),
	mFMODInternetStreamChannelp(NULL),
	mGain(1.0f)
{
	// Number of milliseconds of audio to buffer for the audio card.
	// Must be larger than the usual Second Life frame stutter time.
	const U32 buffer_seconds = 10;		//sec
	const U32 estimated_bitrate = 128;	//kbit/sec
	mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);

	// Here's where we set the size of the network buffer and some buffering
	// parameters.  In this case we want a network buffer of 16k, we want it
	// to prebuffer 40% of that when we first connect, and we want it
	// to rebuffer 80% of that whenever we encounter a buffer underrun.

	// Leave the net buffer properties at the default.
	//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
}

LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
{
	// nothing interesting/safe to do.
}

void LLStreamingAudio_FMODEX::start(const std::string& url)
{
	//if (!mInited)
	//{
	//	llwarns << "startInternetStream before audio initialized" << llendl;
	//	return;
	//}

	// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
	stop();

	if (!url.empty())
	{
		llinfos << "Starting internet stream: " << url << llendl;
		mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
		mURL = url;
	}
	else
	{
		llinfos << "Set internet stream to null" << llendl;
		mURL.clear();
	}
}

void LLStreamingAudio_FMODEX::update()
{
	// Kill dead internet streams, if possible
	std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
	for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
	{
		LLAudioStreamManagerFMODEX *streamp = *iter;
		if (streamp->stopStream())
		{
			llinfos << "Closed dead stream" << llendl;
			delete streamp;
			mDeadStreams.erase(iter++);
		}
		else
		{
			iter++;
		}
	}

	// Don't do anything if there are no streams playing
	if (!mCurrentInternetStreamp)
	{
		return;
	}

	unsigned int progress;
	bool starving;
	bool diskbusy;
	FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy);

	if (open_state == FMOD_OPENSTATE_READY)
	{
		// Stream is live

		// start the stream if it's ready
		if (!mFMODInternetStreamChannelp &&
			(mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
		{
			// Reset volume to previously set volume
			setGain(getGain());
			mFMODInternetStreamChannelp->setPaused(false);
		}
	}
	else if(open_state == FMOD_OPENSTATE_ERROR)
	{
		stop();
		return;
	}

	if(mFMODInternetStreamChannelp)
	{
		FMOD::Sound *sound = NULL;

		if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
		{
			FMOD_TAG tag;
			S32 tagcount, dirtytagcount;

			if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
			{
				for(S32 i = 0; i < tagcount; ++i)
				{
					if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
						continue;

					if (tag.type == FMOD_TAGTYPE_FMOD)
					{
						if (!strcmp(tag.name, "Sample Rate Change"))
						{
							llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl;
							mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
						}
						continue;
					}
				}
			}

			if(starving)
			{
				bool paused = false;
				mFMODInternetStreamChannelp->getPaused(&paused);
				if(!paused)
				{
					llinfos << "Stream starvation detected! Pausing stream until buffer nearly full." << llendl;
					llinfos << "  (diskbusy="<<diskbusy<<")" << llendl;
					llinfos << "  (progress="<<progress<<")" << llendl;
					mFMODInternetStreamChannelp->setPaused(true);
				}
			}
			else if(progress > 80)
			{
				mFMODInternetStreamChannelp->setPaused(false);
			}
		}
	}
}

void LLStreamingAudio_FMODEX::stop()
{
	if (mFMODInternetStreamChannelp)
	{
		mFMODInternetStreamChannelp->setPaused(true);
		mFMODInternetStreamChannelp->setPriority(0);
		mFMODInternetStreamChannelp = NULL;
	}

	if (mCurrentInternetStreamp)
	{
		llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
		if (mCurrentInternetStreamp->stopStream())
		{
			delete mCurrentInternetStreamp;
		}
		else
		{
			llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
			mDeadStreams.push_back(mCurrentInternetStreamp);
		}
		mCurrentInternetStreamp = NULL;
		//mURL.clear();
	}
}

void LLStreamingAudio_FMODEX::pause(int pauseopt)
{
	if (pauseopt < 0)
	{
		pauseopt = mCurrentInternetStreamp ? 1 : 0;
	}

	if (pauseopt)
	{
		if (mCurrentInternetStreamp)
		{
			stop();
		}
	}
	else
	{
		start(getURL());
	}
}

// A stream is "playing" if it has been requested to start.  That
// doesn't necessarily mean audio is coming out of the speakers.
int LLStreamingAudio_FMODEX::isPlaying()
{
	if (mCurrentInternetStreamp)
	{
		return 1; // Active and playing
	}
	else if (!mURL.empty())
	{
		return 2; // "Paused"
	}
	else
	{
		return 0;
	}
}

F32 LLStreamingAudio_FMODEX::getGain()
{
	return mGain;
}

std::string LLStreamingAudio_FMODEX::getURL()
{
	return mURL;
}

void LLStreamingAudio_FMODEX::setGain(F32 vol)
{
	mGain = vol;

	if (mFMODInternetStreamChannelp)
	{
		vol = llclamp(vol * vol, 0.f, 1.f);	//should vol be squared here?

		mFMODInternetStreamChannelp->setVolume(vol);
	}
}

///////////////////////////////////////////////////////
// manager of possibly-multiple internet audio streams

LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
	mSystem(system),
	mStreamChannel(NULL),
	mInternetStream(NULL),
	mReady(false)
{
	mInternetStreamURL = url;

	FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream);

	if (result!= FMOD_OK)
	{
		llwarns << "Couldn't open fmod stream, error "
			<< FMOD_ErrorString(result)
			<< llendl;
		mReady = false;
		return;
	}

	mReady = true;
}

FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
{
	// We need a live and opened stream before we try and play it.
	if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
	{
		llwarns << "No internet stream to start playing!" << llendl;
		return NULL;
	}

	if(mStreamChannel)
		return mStreamChannel;	//Already have a channel for this stream.

	mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
	return mStreamChannel;
}

bool LLAudioStreamManagerFMODEX::stopStream()
{
	if (mInternetStream)
	{

		bool close = true;
		switch (getOpenState())
		{
		case FMOD_OPENSTATE_CONNECTING:
			close = false;
			break;
		default:
			close = true;
		}

		if (close)
		{
			mInternetStream->release();
			mStreamChannel = NULL;
			mInternetStream = NULL;
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		return true;
	}
}

FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
{
	FMOD_OPENSTATE state;
	mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
	return state;
}

void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
{
	mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES);
	FMOD_ADVANCEDSETTINGS settings;
	memset(&settings,0,sizeof(settings));
	settings.cbsize=sizeof(settings);
	settings.defaultDecodeBufferSize = decodebuffertime;//ms
	mSystem->setAdvancedSettings(&settings);
}
<commit_msg>MAINT-2629: limit stream searches to prevent hangs on bad streams<commit_after>/**
 * @file streamingaudio_fmodex.cpp
 * @brief LLStreamingAudio_FMODEX implementation
 *
 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "llmath.h"

#include "fmod.hpp"
#include "fmod_errors.h"

#include "llstreamingaudio_fmodex.h"

class LLAudioStreamManagerFMODEX
{
public:
	LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
	FMOD::Channel* startStream();
	bool stopStream(); // Returns true if the stream was successfully stopped.
	bool ready();

	const std::string& getURL() 	{ return mInternetStreamURL; }

	FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL);
protected:
	FMOD::System* mSystem;
	FMOD::Channel* mStreamChannel;
	FMOD::Sound* mInternetStream;
	bool mReady;

	std::string mInternetStreamURL;
};

//---------------------------------------------------------------------------
// Internet Streaming
//---------------------------------------------------------------------------
LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
	mSystem(system),
	mCurrentInternetStreamp(NULL),
	mFMODInternetStreamChannelp(NULL),
	mGain(1.0f)
{
	// Number of milliseconds of audio to buffer for the audio card.
	// Must be larger than the usual Second Life frame stutter time.
	const U32 buffer_seconds = 10;		//sec
	const U32 estimated_bitrate = 128;	//kbit/sec
	mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);

	// Here's where we set the size of the network buffer and some buffering
	// parameters.  In this case we want a network buffer of 16k, we want it
	// to prebuffer 40% of that when we first connect, and we want it
	// to rebuffer 80% of that whenever we encounter a buffer underrun.

	// Leave the net buffer properties at the default.
	//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
}

LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
{
	// nothing interesting/safe to do.
}

void LLStreamingAudio_FMODEX::start(const std::string& url)
{
	//if (!mInited)
	//{
	//	llwarns << "startInternetStream before audio initialized" << llendl;
	//	return;
	//}

	// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
	stop();

	if (!url.empty())
	{
		llinfos << "Starting internet stream: " << url << llendl;
		mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
		mURL = url;
	}
	else
	{
		llinfos << "Set internet stream to null" << llendl;
		mURL.clear();
	}
}

void LLStreamingAudio_FMODEX::update()
{
	// Kill dead internet streams, if possible
	std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
	for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
	{
		LLAudioStreamManagerFMODEX *streamp = *iter;
		if (streamp->stopStream())
		{
			llinfos << "Closed dead stream" << llendl;
			delete streamp;
			mDeadStreams.erase(iter++);
		}
		else
		{
			iter++;
		}
	}

	// Don't do anything if there are no streams playing
	if (!mCurrentInternetStreamp)
	{
		return;
	}

	unsigned int progress;
	bool starving;
	bool diskbusy;
	FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy);

	if (open_state == FMOD_OPENSTATE_READY)
	{
		// Stream is live

		// start the stream if it's ready
		if (!mFMODInternetStreamChannelp &&
			(mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
		{
			// Reset volume to previously set volume
			setGain(getGain());
			mFMODInternetStreamChannelp->setPaused(false);
		}
	}
	else if(open_state == FMOD_OPENSTATE_ERROR)
	{
		stop();
		return;
	}

	if(mFMODInternetStreamChannelp)
	{
		FMOD::Sound *sound = NULL;

		if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
		{
			FMOD_TAG tag;
			S32 tagcount, dirtytagcount;

			if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
			{
				for(S32 i = 0; i < tagcount; ++i)
				{
					if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
						continue;

					if (tag.type == FMOD_TAGTYPE_FMOD)
					{
						if (!strcmp(tag.name, "Sample Rate Change"))
						{
							llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl;
							mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
						}
						continue;
					}
				}
			}

			if(starving)
			{
				bool paused = false;
				mFMODInternetStreamChannelp->getPaused(&paused);
				if(!paused)
				{
					llinfos << "Stream starvation detected! Pausing stream until buffer nearly full." << llendl;
					llinfos << "  (diskbusy="<<diskbusy<<")" << llendl;
					llinfos << "  (progress="<<progress<<")" << llendl;
					mFMODInternetStreamChannelp->setPaused(true);
				}
			}
			else if(progress > 80)
			{
				mFMODInternetStreamChannelp->setPaused(false);
			}
		}
	}
}

void LLStreamingAudio_FMODEX::stop()
{
	if (mFMODInternetStreamChannelp)
	{
		mFMODInternetStreamChannelp->setPaused(true);
		mFMODInternetStreamChannelp->setPriority(0);
		mFMODInternetStreamChannelp = NULL;
	}

	if (mCurrentInternetStreamp)
	{
		llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
		if (mCurrentInternetStreamp->stopStream())
		{
			delete mCurrentInternetStreamp;
		}
		else
		{
			llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
			mDeadStreams.push_back(mCurrentInternetStreamp);
		}
		mCurrentInternetStreamp = NULL;
		//mURL.clear();
	}
}

void LLStreamingAudio_FMODEX::pause(int pauseopt)
{
	if (pauseopt < 0)
	{
		pauseopt = mCurrentInternetStreamp ? 1 : 0;
	}

	if (pauseopt)
	{
		if (mCurrentInternetStreamp)
		{
			stop();
		}
	}
	else
	{
		start(getURL());
	}
}

// A stream is "playing" if it has been requested to start.  That
// doesn't necessarily mean audio is coming out of the speakers.
int LLStreamingAudio_FMODEX::isPlaying()
{
	if (mCurrentInternetStreamp)
	{
		return 1; // Active and playing
	}
	else if (!mURL.empty())
	{
		return 2; // "Paused"
	}
	else
	{
		return 0;
	}
}

F32 LLStreamingAudio_FMODEX::getGain()
{
	return mGain;
}

std::string LLStreamingAudio_FMODEX::getURL()
{
	return mURL;
}

void LLStreamingAudio_FMODEX::setGain(F32 vol)
{
	mGain = vol;

	if (mFMODInternetStreamChannelp)
	{
		vol = llclamp(vol * vol, 0.f, 1.f);	//should vol be squared here?

		mFMODInternetStreamChannelp->setVolume(vol);
	}
}

///////////////////////////////////////////////////////
// manager of possibly-multiple internet audio streams

LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
	mSystem(system),
	mStreamChannel(NULL),
	mInternetStream(NULL),
	mReady(false)
{
	mInternetStreamURL = url;

	FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream);

	if (result!= FMOD_OK)
	{
		llwarns << "Couldn't open fmod stream, error "
			<< FMOD_ErrorString(result)
			<< llendl;
		mReady = false;
		return;
	}

	mReady = true;
}

FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
{
	// We need a live and opened stream before we try and play it.
	if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
	{
		llwarns << "No internet stream to start playing!" << llendl;
		return NULL;
	}

	if(mStreamChannel)
		return mStreamChannel;	//Already have a channel for this stream.

	mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
	return mStreamChannel;
}

bool LLAudioStreamManagerFMODEX::stopStream()
{
	if (mInternetStream)
	{

		bool close = true;
		switch (getOpenState())
		{
		case FMOD_OPENSTATE_CONNECTING:
			close = false;
			break;
		default:
			close = true;
		}

		if (close)
		{
			mInternetStream->release();
			mStreamChannel = NULL;
			mInternetStream = NULL;
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		return true;
	}
}

FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
{
	FMOD_OPENSTATE state;
	mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
	return state;
}

void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
{
	mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES);
	FMOD_ADVANCEDSETTINGS settings;
	memset(&settings,0,sizeof(settings));
	settings.cbsize=sizeof(settings);
	settings.defaultDecodeBufferSize = decodebuffertime;//ms
	mSystem->setAdvancedSettings(&settings);
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

void example()
{
    std::list<Item> items = new std::list<Item>();
    items.push_back(new Item("+5 Dexterity Vest", 10, 20));
    items.push_back(new Item("Aged Brie", 2, 0));
    items.push_back(new Item("Elixir of the Mongoose", 5, 7));
    items.push_back(new Item("Sulfuras, Hand of Ragnaros", 0, 80));
    items.push_back(new Item("Backstage passes to a TAFKAL80ETC concert", 15, 20));
    items.push_back(new Item("Conjured Mana Cake", 3, 6));
    GildedRose app = new GildedRose(items);
    app.updateQuality();
}

class GildedRose
{
public:
    std::list<Item> items;
    GildedRose(std::list items)
    {
        this.items = items;
    }

    void updateQuality()
    {
        for (int i = 0; i < items.length; i++)
        {
            if (items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert")
            {
                if (items[i].quality > 0)
                {
                    if (items[i].name != "Sulfuras, Hand of Ragnaros")
                    {
                        items[i].quality = items[i].quality - 1;
                    }
                }
            }
            else
            {
                if (items[i].quality < 50)
                {
                    items[i].quality = items[i].quality + 1;

                    if (items[i].name == "Backstage passes to a TAFKAL80ETC concert")
                    {
                        if (items[i].sellIn < 11)
                        {
                            if (items[i].quality < 50)
                            {
                                items[i].quality = items[i].quality + 1;
                            }
                        }

                        if (items[i].sellIn < 6)
                        {
                            if (items[i].quality < 50)
                            {
                                items[i].quality = items[i].quality + 1;
                            }
                        }
                    }
                }
            }

            if (items[i].name != "Sulfuras, Hand of Ragnaros")
            {
                items[i].sellIn = items[i].sellIn - 1;
            }

            if (items[i].sellIn < 0)
            {
                if (items[i].name != "Aged Brie")
                {
                    if (items[i].name != "Backstage passes to a TAFKAL80ETC concert")
                    {
                        if (items[i].quality > 0)
                        {
                            if (items[i].name != "Sulfuras, Hand of Ragnaros")
                            {
                                items[i].quality = items[i].quality - 1;
                            }
                        }
                    }
                    else
                    {
                        items[i].quality = items[i].quality - items[i].quality;
                    }
                }
                else
                {
                    if (items[i].quality < 50)
                    {
                        items[i].quality = items[i].quality + 1;
                    }
                }
            }
        }
    }
};

class Item
{
public:
    std::string name;
    int sellIn;
    int quality;
};

TEST(GildedRoseTest, Foo) {
    std::list<Item> items = new std::list<Item>();
    items.push_back(new Item("Foo", 0, 0));
    GildedRose app = new GildedRose(items);
    app.updateQuality();
    EXPECT_EQ("fixme", app.items[0].name);
}

<commit_msg>C++ version with a vector to hold the items.<commit_after>#include <gtest/gtest.h>

#include <string>

using namespace std;

class Item
{
public:
    string name;
    int sellIn;
    int quality;
    Item(string name, int sellIn, int quality) : name(name), sellIn(sellIn), quality(quality)
    {}
};

class GildedRose
{
public:
    vector<Item> items;
    GildedRose(vector<Item> items) : items (items)
    {}

    void updateQuality()
    {
        for (int i = 0; i < items.size(); i++)
        {
            if (items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert")
            {
                if (items[i].quality > 0)
                {
                    if (items[i].name != "Sulfuras, Hand of Ragnaros")
                    {
                        items[i].quality = items[i].quality - 1;
                    }
                }
            }
            else
            {
                if (items[i].quality < 50)
                {
                    items[i].quality = items[i].quality + 1;

                    if (items[i].name == "Backstage passes to a TAFKAL80ETC concert")
                    {
                        if (items[i].sellIn < 11)
                        {
                            if (items[i].quality < 50)
                            {
                                items[i].quality = items[i].quality + 1;
                            }
                        }

                        if (items[i].sellIn < 6)
                        {
                            if (items[i].quality < 50)
                            {
                                items[i].quality = items[i].quality + 1;
                            }
                        }
                    }
                }
            }

            if (items[i].name != "Sulfuras, Hand of Ragnaros")
            {
                items[i].sellIn = items[i].sellIn - 1;
            }

            if (items[i].sellIn < 0)
            {
                if (items[i].name != "Aged Brie")
                {
                    if (items[i].name != "Backstage passes to a TAFKAL80ETC concert")
                    {
                        if (items[i].quality > 0)
                        {
                            if (items[i].name != "Sulfuras, Hand of Ragnaros")
                            {
                                items[i].quality = items[i].quality - 1;
                            }
                        }
                    }
                    else
                    {
                        items[i].quality = items[i].quality - items[i].quality;
                    }
                }
                else
                {
                    if (items[i].quality < 50)
                    {
                        items[i].quality = items[i].quality + 1;
                    }
                }
            }
        }
    }
};

void example()
{
    vector<Item> items;
    items.push_back(Item("+5 Dexterity Vest", 10, 20));
    items.push_back(Item("Aged Brie", 2, 0));
    items.push_back(Item("Elixir of the Mongoose", 5, 7));
    items.push_back(Item("Sulfuras, Hand of Ragnaros", 0, 80));
    items.push_back(Item("Backstage passes to a TAFKAL80ETC concert", 15, 20));
    items.push_back(Item("Conjured Mana Cake", 3, 6));
    GildedRose app(items);
    app.updateQuality();
}

TEST(GildedRoseTest, Foo) {
    vector<Item> items;
    items.push_back(Item("Foo", 0, 0));
    GildedRose app(items);
    app.updateQuality();
    EXPECT_EQ("fixme", app.items[0].name);
}

<|endoftext|>