text:
// Copyright (c) 2012-2018 The Elastos Open Source Project
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <stdlib.h>
#include <boost/scoped_ptr.hpp>
#include <Core/BRTransaction.h>
#include <SDK/ELACoreExt/ELATxOutput.h>
#include <boost/function.hpp>
#include <SDK/Common/Log.h>
#include <Core/BRAddress.h>
#include <Core/BRBIP32Sequence.h>
#include <Core/BRWallet.h>
#include <SDK/Transaction/Transaction.h>
#include <SDK/Common/ParamChecker.h>

#include "BRAddress.h"
#include "BRBIP39Mnemonic.h"
#include "BRArray.h"
#include "BRTransaction.h"

#include "Wallet.h"
#include "Utils.h"
#include "ELACoreExt/ELATransaction.h"
#include "ELATxOutput.h"
#include "Account/MultiSignSubAccount.h"

namespace Elastos {
	namespace ElaWallet {

		typedef struct UTXO {
			BRUTXO o;
			uint64_t amount;
		} UTXO_t;

		ELAWallet *ELAWalletNew(BRTransaction *transactions[], size_t txCount,
								size_t (*WalletUnusedAddrs)(BRWallet *wallet, BRAddress addrs[], uint32_t gapLimit,
															int internal),
								size_t (*WalletAllAddrs)(BRWallet *wallet, BRAddress addrs[], size_t addrsCount),
								void (*setApplyFreeTx)(void *info, void *tx),
								void (*WalletUpdateBalance)(BRWallet *wallet),
								int (*WalletContainsTx)(BRWallet *wallet, const BRTransaction *tx),
								void (*WalletAddUsedAddrs)(BRWallet *wallet, const BRTransaction *tx),
								BRTransaction *(*WalletCreateTxForOutputs)(BRWallet *wallet,
																		   const BRTxOutput outputs[],
																		   size_t outCount),
								uint64_t (*WalletMaxOutputAmount)(BRWallet *wallet),
								uint64_t (*WalletFeeForTx)(BRWallet *wallet, const BRTransaction *tx),
								int (*TransactionIsSigned)(const BRTransaction *tx),
								size_t (*KeyToAddress)(const BRKey *key, char *addr, size_t addrLen),
								uint64_t (*balanceAfterTx)(BRWallet *wallet, const BRTransaction *tx)) {
			ELAWallet *wallet = NULL;
			BRTransaction *tx;

			assert(transactions != NULL || txCount == 0);
			wallet = new ELAWallet();
			assert(wallet != NULL);
			array_new(wallet->Raw.utxos, 100);
			array_new(wallet->Raw.transactions, txCount + 100);
			wallet->Raw.feePerKb = DEFAULT_FEE_PER_KB;
			wallet->Raw.lastBlockHeight = 0;
			wallet->Raw.WalletUnusedAddrs = WalletUnusedAddrs;
			wallet->Raw.WalletAllAddrs = WalletAllAddrs;
			wallet->Raw.setApplyFreeTx = setApplyFreeTx;
			wallet->Raw.WalletUpdateBalance = WalletUpdateBalance;
			wallet->Raw.WalletContainsTx = WalletContainsTx;
			wallet->Raw.WalletAddUsedAddrs = WalletAddUsedAddrs;
			wallet->Raw.WalletCreateTxForOutputs = WalletCreateTxForOutputs;
			wallet->Raw.WalletMaxOutputAmount = WalletMaxOutputAmount;
			wallet->Raw.WalletFeeForTx = WalletFeeForTx;
			wallet->Raw.TransactionIsSigned = TransactionIsSigned;
			wallet->Raw.KeyToAddress = KeyToAddress;
			wallet->Raw.balanceAfterTx = balanceAfterTx;
			array_new(wallet->Raw.internalChain, 100);
			array_new(wallet->Raw.externalChain, 100);
			array_new(wallet->Raw.balanceHist, txCount + 100);
			wallet->Raw.allTx = BRSetNew(BRTransactionHash, BRTransactionEq, txCount + 100);
			wallet->Raw.invalidTx = BRSetNew(BRTransactionHash, BRTransactionEq, 10);
			wallet->Raw.pendingTx = BRSetNew(BRTransactionHash, BRTransactionEq, 10);
			wallet->Raw.spentOutputs = BRSetNew(BRUTXOHash, BRUTXOEq, txCount + 100);
			wallet->Raw.usedAddrs = BRSetNew(BRAddressHash, BRAddressEq, txCount + 100);
			wallet->Raw.allAddrs = BRSetNew(BRAddressHash, BRAddressEq, txCount + 100);
			wallet->TxRemarkMap = ELAWallet::TransactionRemarkMap();
			wallet->ListeningAddrs = std::vector<std::string>();
			pthread_mutex_init(&wallet->Raw.lock, NULL);

			for (size_t i = 0; transactions && i < txCount; i++) {
				tx = transactions[i];
				if (!wallet->Raw.TransactionIsSigned(tx) || BRSetContains(wallet->Raw.allTx, tx)) continue;
				BRSetAdd(wallet->Raw.allTx, tx);
				_BRWalletInsertTx((BRWallet *) wallet, tx);
			}

			return wallet;
		}

		void ELAWalletFree(ELAWallet *wallet, bool freeInternal) {
			assert(wallet != NULL);
			pthread_mutex_lock(&wallet->Raw.lock);
			BRSetFree(wallet->Raw.allAddrs);
			BRSetFree(wallet->Raw.usedAddrs);
			BRSetFree(wallet->Raw.invalidTx);
			BRSetFree(wallet->Raw.pendingTx);
			BRSetApply(wallet->Raw.allTx, NULL, wallet->Raw.setApplyFreeTx);
			BRSetFree(wallet->Raw.allTx);
			BRSetFree(wallet->Raw.spentOutputs);
			if (freeInternal)
				array_free(wallet->Raw.internalChain);
			array_free(wallet->Raw.externalChain);
			array_free(wallet->Raw.balanceHist);
			array_free(wallet->Raw.transactions);
			array_free(wallet->Raw.utxos);
			pthread_mutex_unlock(&wallet->Raw.lock);
			pthread_mutex_destroy(&wallet->Raw.lock);

			delete wallet;
		}

		std::string ELAWalletGetRemark(ELAWallet *wallet, const std::string &txHash) {
			if (wallet->TxRemarkMap.find(txHash) == wallet->TxRemarkMap.end())
				return "";
			return wallet->TxRemarkMap[txHash];
		}

		void ELAWalletRegisterRemark(ELAWallet *wallet, const std::string &txHash,
									 const std::string &remark) {
			wallet->TxRemarkMap[txHash] = remark;
		}

		void ELAWalletLoadRemarks(ELAWallet *wallet,
								  const SharedWrapperList<Transaction, BRTransaction *> &transaction) {
			for (int i = 0; i < transaction.size(); ++i) {
				wallet->TxRemarkMap[Utils::UInt256ToString(transaction[i]->getHash())] =
					((ELATransaction *) transaction[i]->getRaw())->Remark;
			}
		}

		int UTXOCompareAscending(const void *o1, const void *o2) {
			if (((const UTXO_t *)o1)->amount > ((const UTXO_t *)o2)->amount) return 1;
			if (((const UTXO_t *)o1)->amount < ((const UTXO_t *)o2)->amount) return -1;
			return 0;
		}

		int UTXOCompareDescending(const void *o1, const void *o2) {
			if (((const UTXO_t *)o1)->amount < ((const UTXO_t *)o2)->amount) return 1;
			if (((const UTXO_t *)o1)->amount > ((const UTXO_t *)o2)->amount) return -1;
			return 0;
		}

		Wallet::Wallet() {

		}

		Wallet::Wallet(const SharedWrapperList<Transaction, BRTransaction *> &transactions,
					   const SubAccountPtr &subAccount,
					   const boost::shared_ptr<Listener> &listener) :
			_subAccount(subAccount) {

			_wallet = ELAWalletNew(transactions.getRawPointerArray().data(), transactions.size(),
								   WalletUnusedAddrs, WalletAllAddrs, setApplyFreeTx, WalletUpdateBalance,
								   WalletContainsTx, WalletAddUsedAddrs, WalletCreateTxForOutputs,
								   WalletMaxOutputAmount, WalletFeeForTx, TransactionIsSigned, KeyToAddress,
								   BalanceAfterTx);
			_subAccount->InitWallet(transactions.getRawPointerArray().data(), transactions.size(), _wallet);

			assert(listener != nullptr);
			_listener = boost::weak_ptr<Listener>(listener);

			Log::getLogger()->info("_wallet = {:p}, listener = {:p}", (void *) _wallet, (void *) listener.get());
			ParamChecker::checkCondition(_wallet == nullptr, Error::Wallet, "Create new wallet");

			BRWalletSetCallbacks((BRWallet *) _wallet, &_listener,
								 balanceChanged,
								 txAdded,
								 txUpdated,
								 txDeleted);

			typedef SharedWrapperList<Transaction, BRTransaction *> Transactions;
			for (Transactions::const_iterator it = transactions.cbegin(); it != transactions.cend(); ++it) {
				(*it)->isRegistered() = true;
			}

			ELAWalletLoadRemarks(_wallet, transactions);
		}

		Wallet::~Wallet() {
			if (_wallet != nullptr) {
				ELAWalletFree(_wallet);
				_wallet = nullptr;
			}
		}

		void Wallet::initListeningAddresses(const std::vector<std::string> &addrs) {
			_wallet->ListeningAddrs = addrs;
		}

		std::string Wallet::toString() const {
			//todo complete me
			return "";
		}

		BRWallet *Wallet::getRaw() const {
			return (BRWallet *) _wallet;
		}

		void Wallet::RegisterRemark(const TransactionPtr &transaction) {
			ELAWalletRegisterRemark(_wallet,
									Utils::UInt256ToString(transaction->getHash()),
									((ELATransaction *) transaction->getRaw())->Remark);
		}

		std::string Wallet::GetRemark(const std::string &txHash) {
			return ELAWalletGetRemark(_wallet, txHash);
		}

		nlohmann::json Wallet::GetBalanceInfo() {

			size_t utxosCount = BRWalletUTXOs((BRWallet *) _wallet, nullptr, 0);
			BRUTXO utxos[utxosCount];
			BRWalletUTXOs((BRWallet *) _wallet, utxos, utxosCount);

			nlohmann::json j;

			ELATransaction *t;
			std::map<std::string, uint64_t> addressesBalanceMap;
			pthread_mutex_lock(&_wallet->Raw.lock);
			for (size_t i = 0; i < utxosCount; ++i) {
				void *tempPtr = BRSetGet(_wallet->Raw.allTx, &utxos[utxosCount].hash);
				if (tempPtr == nullptr) continue;
				t = static_cast<ELATransaction *>(tempPtr);

				if (addressesBalanceMap.find(t->outputs[utxos->n]->getAddress()) != addressesBalanceMap.end()) {
					addressesBalanceMap[t->outputs[utxos->n]->getAddress()] += t->outputs[utxos->n]->getAmount();
				} else {
					addressesBalanceMap[t->outputs[utxos->n]->getAddress()] = t->outputs[utxos->n]->getAmount();
				}
			}
			pthread_mutex_unlock(&_wallet->Raw.lock);

			std::vector<nlohmann::json> balances;
			std::for_each(addressesBalanceMap.begin(), addressesBalanceMap.end(),
						  [&addressesBalanceMap, &balances](const std::map<std::string, uint64_t>::value_type &item) {
							  nlohmann::json balanceKeyValue;
							  balanceKeyValue[item.first] = item.second;
							  balances.push_back(balanceKeyValue);
						  });

			j["Balances"] = balances;
			return j;
		}

		uint64_t Wallet::GetBalanceWithAddress(const std::string &address) {
			size_t utxosCount = BRWalletUTXOs((BRWallet *) _wallet, nullptr, 0);
			BRUTXO utxos[utxosCount];
			BRWalletUTXOs((BRWallet *) _wallet, utxos, utxosCount);

			ELATransaction *t;
			uint64_t balance = 0;
			pthread_mutex_lock(&_wallet->Raw.lock);
			for (size_t i = 0; i < utxosCount; ++i) {
				void *tempPtr = BRSetGet(_wallet->Raw.allTx, &utxos[i].hash);
				if (tempPtr == nullptr) continue;
				t = static_cast<ELATransaction *>(tempPtr);
				if (BRAddressEq(t->outputs[utxos[i].n]->getRaw()->address, address.c_str())) {
					balance += t->outputs[utxos[i].n]->getAmount();
				}
			}
			pthread_mutex_unlock(&_wallet->Raw.lock);

			return balance;
		}

		SharedWrapperList<Transaction, BRTransaction *> Wallet::getTransactions() const {

			size_t transactionCount = BRWalletTransactions((BRWallet *) _wallet, NULL, 0);

			BRTransaction **transactions = (BRTransaction **) calloc(transactionCount, sizeof(BRTransaction *));
			transactionCount = BRWalletTransactions((BRWallet *) _wallet, transactions, transactionCount);

			SharedWrapperList<Transaction, BRTransaction *> results(transactionCount);
			// TODO: Decide if copy is okay; if not, be sure to mark 'isRegistered = true'
			//   We should not copy; but we need to deal with wallet-initiated 'free'
			for (int index = 0; index < transactionCount; index++) {
				results.push_back(TransactionPtr(new Transaction(*(ELATransaction *) transactions[index])));
			}

			if (NULL != transactions) free(transactions);
			return results;
		}

		SharedWrapperList<Transaction, BRTransaction *>
		Wallet::getTransactionsConfirmedBefore(uint32_t blockHeight) const {

			size_t transactionCount = BRWalletTxUnconfirmedBefore((BRWallet *) _wallet, NULL, 0, blockHeight);

			BRTransaction **transactions = (BRTransaction **) calloc(transactionCount, sizeof(BRTransaction *));
			transactionCount = BRWalletTxUnconfirmedBefore((BRWallet *) _wallet, transactions, transactionCount,
														   blockHeight);

			SharedWrapperList<Transaction, BRTransaction *> results(transactionCount);
			for (int index = 0; index < transactionCount; index++) {
				results.push_back(TransactionPtr(new Transaction(*(ELATransaction *) transactions[index])));
			}

			if (NULL != transactions) free(transactions);
			return results;
		}

		uint64_t Wallet::getBalance() const {
			return BRWalletBalance((BRWallet *) _wallet);
		}

		uint64_t Wallet::getTotalSent() {
			return BRWalletTotalSent((BRWallet *) _wallet);
		}

		uint64_t Wallet::getTotalReceived() {
			return BRWalletTotalReceived((BRWallet *) _wallet);
		}

		uint64_t Wallet::getFeePerKb() {
			return BRWalletFeePerKb((BRWallet *) _wallet);
		}

		void Wallet::setFeePerKb(uint64_t feePerKb) {
			BRWalletSetFeePerKb((BRWallet *) _wallet, feePerKb);
		}

		uint64_t Wallet::getMaxFeePerKb() {
			return MAX_FEE_PER_KB;
		}

		uint64_t Wallet::getDefaultFeePerKb() {
			return DEFAULT_FEE_PER_KB;
		}

		bool Wallet::AddressFilter(const std::string &fromAddress, const std::string &filterAddress) {
			return filterAddress == fromAddress;
		}

		void Wallet::SortUTXOForAmount(BRWallet *wallet, uint64_t amount) {
			if (array_count(wallet->utxos) <= 1)
				return;

			UTXO_t *utxos;
			BRUTXO *o;
			ELATransaction *tx;
			array_new(utxos, array_count(wallet->utxos));

			for (size_t i = 0; i < array_count(wallet->utxos); ++i) {
				o = &wallet->utxos[i];
				tx = (ELATransaction *) BRSetGet(wallet->allTx, o);
				if (!tx || o->n >= tx->outputs.size()) {
					Log::getLogger()->error("Invalid utxo {} n={}", Utils::UInt256ToString(o->hash), o->n);
					continue;
				}

				array_add(utxos, ((UTXO_t){*o, tx->outputs[o->n]->getAmount()}));
			}

			qsort(utxos, array_count(utxos), sizeof(*utxos), UTXOCompareAscending);

			uint64_t Threshold = amount * 2 + wallet->feePerKb;
			size_t ThresholdIndex = 0;
			for (size_t i = 0; i < array_count(utxos); ++i) {
				if (utxos[i].amount > Threshold) {
					ThresholdIndex = i;
					break;
				}
			}

			if (ThresholdIndex > 0)
				qsort(utxos, ThresholdIndex, sizeof(*utxos), UTXOCompareDescending);

			array_set_count(wallet->utxos, 0);

			for (size_t i = 0; i < array_count(utxos); ++i) {
				array_add(wallet->utxos, utxos[i].o);
			}

			array_free(utxos);
		}

		BRTransaction *Wallet::CreateTxForOutputs(BRWallet *wallet, const BRTxOutput outputs[], size_t outCount,
												  uint64_t fee, const std::string &fromAddress,
												  bool(*filter)(const std::string &fromAddress,
																const std::string &addr)) {
			ELATransaction *tx, *transaction = ELATransactionNew();
			uint64_t feeAmount, amount = 0, balance = 0;
			size_t i, cpfpSize = 0;
			BRUTXO *o;
			BRAddress addr = BR_ADDRESS_NONE;
			TransactionPtr txn(new Transaction(transaction, false));

			assert(wallet != NULL);
			ParamChecker::checkCondition(outputs == NULL || outCount == 0, Error::CreateTransaction, "Invalid outputs");

			for (i = 0; outputs && i < outCount; i++) {
				ELATxOutput *ELAOutput = (ELATxOutput *)&outputs[i];

				transaction->outputs.push_back(new TransactionOutput(ELAOutput->raw.address, ELAOutput->raw.amount,
																	 ELAOutput->assetId));
				amount += outputs[i].amount;
			}

			pthread_mutex_lock(&wallet->lock);
			feeAmount = txn->calculateFee(wallet->feePerKb);

			SortUTXOForAmount(wallet, amount);
			// TODO: use up all UTXOs for all used addresses to avoid leaving funds in addresses whose public key is revealed
			// TODO: avoid combining addresses in a single transaction when possible to reduce information leakage
			// TODO: use up UTXOs received from any of the output scripts that this transaction sends funds to, to mitigate an
			//       attacker double spending and requesting a refund
			for (i = 0; i < array_count(wallet->utxos); i++) {
				o = &wallet->utxos[i];
				tx = (ELATransaction *) BRSetGet(wallet->allTx, o);
				if (!tx || o->n >= tx->outputs.size()) continue;
				if (filter && !fromAddress.empty() && !filter(fromAddress, tx->outputs[o->n]->getAddress())) {
					continue;
				}

				if (tx->raw.blockHeight >= wallet->lastBlockHeight) {
					Log::getLogger()->warn("utxo: '{}' n: '{}', confirming, can't spend for now, tx height = {}, wallet block height = {}",
										   Utils::UInt256ToString(tx->raw.txHash, true), o->n, tx->raw.blockHeight, wallet->lastBlockHeight);
					continue;
				}

				BRTransactionAddInput(&transaction->raw, tx->raw.txHash, o->n, tx->outputs[o->n]->getAmount(),
									  tx->outputs[o->n]->getRaw()->script, tx->outputs[o->n]->getRaw()->scriptLen,
									  nullptr, 0, TXIN_SEQUENCE);
				std::string addr = Utils::UInt168ToAddress(tx->outputs[o->n]->getProgramHash());
				size_t inCount = transaction->raw.inCount;
				BRTxInput *input = &transaction->raw.inputs[inCount - 1];
				memset(input->address, 0, sizeof(input->address));
				strncpy(input->address, addr.c_str(), sizeof(input->address) - 1);

				if (txn->getSize() + TX_RECHARGE_OUTPUT_SIZE > TX_MAX_SIZE) { // transaction size-in-bytes too large
					bool balanceEnough = true;
					feeAmount = txn->calculateFee(wallet->feePerKb) + wallet->feePerKb;
					ELATransactionFree(transaction);
					transaction = nullptr;

					// check for sufficient total funds before building a smaller transaction
					if (wallet->balance < amount + feeAmount) {
						Log::getLogger()->error("Not enough sufficient total funds for building a smaller tx.");
						balanceEnough = false;
					}

					pthread_mutex_unlock(&wallet->lock);

					ParamChecker::checkCondition(!balanceEnough, Error::CreateTransaction,
												 "Available token is not enough");

					uint64_t maxAmount = 0;
					if (outputs[outCount - 1].amount > (amount + feeAmount - balance)) {
						for (int j = 0; j < outCount - 1; ++j) {
							maxAmount += outputs[j].amount;
						}
						maxAmount += outputs[outCount - 1].amount - (amount + feeAmount - balance);
						ParamChecker::checkCondition(true, Error::CreateTransactionExceedSize,
													 "Tx size too large, amount should less than " +
													 std::to_string(maxAmount), maxAmount);
					} else {
						for (int j = 0; j < outCount - 1; ++j) {
							maxAmount += outputs[j].amount;
						}
						ParamChecker::checkCondition(true, Error::CreateTransactionExceedSize,
													 "Tx size too large, amount should less than " +
													 std::to_string(maxAmount), maxAmount);
					}

					balance = amount = feeAmount = 0;
					pthread_mutex_lock(&wallet->lock);
					break;
				}

				balance += tx->outputs[o->n]->getAmount();

//        // size of unconfirmed, non-change inputs for child-pays-for-parent fee
//        // don't include parent tx with more than 10 inputs or 10 outputs
//        if (tx->blockHeight == TX_UNCONFIRMED && tx->inCount <= 10 && tx->outCount <= 10 &&
//            ! _BRWalletTxIsSend(wallet, tx)) cpfpSize += BRTransactionSize(tx);

				// fee amount after adding a change output
				feeAmount = txn->calculateFee(wallet->feePerKb);

				// increase fee to round off remaining wallet balance to nearest 100 satoshi
				//if (wallet->balance > amount + feeAmount) feeAmount += (wallet->balance - (amount + feeAmount)) % 100;

				if (balance >= amount + feeAmount) break;
			}

			pthread_mutex_unlock(&wallet->lock);

			if (transaction != nullptr) {
				transaction->fee = feeAmount;
			}

			if (transaction && (outCount < 1 || balance < amount + feeAmount)) { // no outputs/insufficient funds
				ELATransactionFree(transaction);
				transaction = nullptr;
				ParamChecker::checkCondition(balance < amount + feeAmount, Error::BalanceNotEnough,
											 "Available token is not enough");
				ParamChecker::checkCondition(outCount < 1, Error::CreateTransaction, "Output count is not enough");
			} else if (transaction && balance - (amount + feeAmount) > 0) { // add change output
				wallet->WalletUnusedAddrs(wallet, &addr, 1, 1);

				UInt256 assetID = transaction->outputs[0]->getAssetId();

				TransactionOutput *output = new TransactionOutput(addr.s, balance - (amount + feeAmount), assetID);

				transaction->outputs.push_back(output);
			}

			return (BRTransaction *) transaction;
		}

		BRTransaction *Wallet::WalletCreateTxForOutputs(BRWallet *wallet, const BRTxOutput outputs[], size_t outCount) {
			return CreateTxForOutputs(wallet, outputs, outCount, 0, "", nullptr);
		}

		TransactionPtr
		Wallet::createTransaction(const std::string &fromAddress, uint64_t fee, uint64_t amount,
								  const std::string &toAddress, const std::string &remark,
								  const std::string &memo) {
			UInt168 u168Address = UINT168_ZERO;
			ParamChecker::checkCondition(!fromAddress.empty() && !Utils::UInt168FromAddress(u168Address, fromAddress),
										 Error::CreateTransaction, "Invalid spender address " + fromAddress);

			ParamChecker::checkCondition(!Utils::UInt168FromAddress(u168Address, toAddress), Error::CreateTransaction,
										 "Invalid receiver address " + toAddress);

			TransactionOutputPtr output = TransactionOutputPtr(new TransactionOutput(
				toAddress, amount, Key::getSystemAssetId()));

			BRTxOutput outputs[1];
			outputs[0] = *output->getRaw();

			ELATransaction *tx = (ELATransaction *) CreateTxForOutputs((BRWallet *) _wallet, outputs, 1, fee,
																	   fromAddress, AddressFilter);

			TransactionPtr result = nullptr;
			if (tx != nullptr) {
				result = TransactionPtr(new Transaction(tx));
				result->setRemark(remark);

				result->addAttribute(
					new Attribute(Attribute::Nonce, Utils::convertToMemBlock(std::to_string(std::rand()))));
				if (!memo.empty())
					result->addAttribute(new Attribute(Attribute::Memo, Utils::convertToMemBlock(memo)));
				if (tx->type == ELATransaction::TransferCrossChainAsset)
					result->addAttribute(
						new Attribute(Attribute::Confirmations, Utils::convertToMemBlock(std::to_string(1))));
			}

			return result;
		}

		bool Wallet::containsTransaction(const TransactionPtr &transaction) {
			return BRWalletContainsTransaction((BRWallet *) _wallet, transaction->getRaw()) != 0;
		}

		bool Wallet::inputFromWallet(const BRTxInput *in) {
			BRWallet *wallet = &_wallet->Raw;
			for (size_t i = 0; i < array_count(wallet->transactions); i++) {
				ELATransaction *tx = (ELATransaction *) wallet->transactions[i];
				if (UInt256Eq(&in->txHash, &tx->raw.txHash)) {
					if (containsAddress(tx->outputs[in->index]->getAddress())) {
						return true;
					}
				}
			}

			return false;
		}

		bool Wallet::registerTransaction(const TransactionPtr &transaction) {
			return BRWalletRegisterTransaction((BRWallet *) _wallet, transaction->getRaw()) != 0;
		}

		void Wallet::removeTransaction(const UInt256 &transactionHash) {
			BRWalletRemoveTransaction((BRWallet *) _wallet, transactionHash);
		}

		void Wallet::updateTransactions(
			const std::vector<UInt256> &transactionsHashes, uint32_t blockHeight, uint32_t timestamp) {
			BRWalletUpdateTransactions((BRWallet *) _wallet, transactionsHashes.data(),
									   transactionsHashes.size(), blockHeight, timestamp);
		}

		TransactionPtr Wallet::transactionForHash(const UInt256 &transactionHash) {

			BRTransaction *transaction = BRWalletTransactionForHash((BRWallet *) _wallet, transactionHash);
			return TransactionPtr(new Transaction(*(ELATransaction *) transaction));
		}

		bool Wallet::transactionIsValid(const TransactionPtr &transaction) {
			return BRWalletTransactionIsValid((BRWallet *) _wallet, transaction->getRaw()) != 0;
		}

		bool Wallet::transactionIsPending(const TransactionPtr &transaction) {
			return BRWalletTransactionIsPending((BRWallet *) _wallet, transaction->getRaw()) != 0;
		}

		bool Wallet::transactionIsVerified(const TransactionPtr &transaction) {
			return BRWalletTransactionIsVerified((BRWallet *) _wallet, transaction->getRaw()) != 0;
		}

		uint64_t Wallet::getTransactionAmount(const TransactionPtr &tx) {
			uint64_t amountSent = getTransactionAmountSent(tx);
			uint64_t amountReceived = getTransactionAmountReceived(tx);

			return amountSent == 0
				   ? amountReceived
				   : -1 * (amountSent - amountReceived + getTransactionFee(tx));
		}

		uint64_t Wallet::getTransactionFee(const TransactionPtr &tx) {
			return WalletFeeForTx((BRWallet *) _wallet, tx->getRaw());
		}

		uint64_t Wallet::getTransactionAmountSent(const TransactionPtr &tx) {

			return BRWalletAmountSentByTx((BRWallet *) _wallet, tx->getRaw());
		}

		uint64_t Wallet::getTransactionAmountReceived(const TransactionPtr &tx) {

			return BRWalletAmountReceivedFromTx((BRWallet *) _wallet, tx->getRaw());
		}

		uint64_t Wallet::getBalanceAfterTransaction(const TransactionPtr &transaction) {

			return _wallet->Raw.balanceAfterTx((BRWallet *) _wallet, transaction->getRaw());
		}

		std::string Wallet::getTransactionAddress(const TransactionPtr &transaction) {

			return getTransactionAmount(transaction) > 0
				   ? getTransactionAddressInputs(transaction)   // we received -> from inputs
				   : getTransactionAddressOutputs(transaction); // we sent     -> to outputs
		}

		std::string Wallet::getTransactionAddressInputs(const TransactionPtr &transaction) {

			for (size_t i = 0; i < transaction->getRaw()->inCount; i++) {

				std::string address = transaction->getRaw()->inputs[i].address;
				if (!containsAddress(address))
					return address;
			}
			return "";
		}

		std::string Wallet::getTransactionAddressOutputs(const TransactionPtr &transaction) {

			const std::vector<TransactionOutput *> &outputs = transaction->getOutputs();
			for (size_t i = 0; i < outputs.size(); i++) {

				std::string address = outputs[i]->getAddress();
				if (!containsAddress(address))
					return address;
			}
			return "";
		}

		uint64_t Wallet::getFeeForTransactionSize(size_t size) {
			return BRWalletFeeForTxSize((BRWallet *) _wallet, size);
		}

		uint64_t Wallet::getMinOutputAmount() {

			return BRWalletMinOutputAmount((BRWallet *) _wallet);
		}

		uint64_t Wallet::getMaxOutputAmount() {

			return WalletMaxOutputAmount((BRWallet *) _wallet);
		}

		std::string Wallet::getReceiveAddress() const {

			return BRWalletReceiveAddress((BRWallet *) _wallet).s;
		}

		std::vector<std::string> Wallet::getAllAddresses() {

			size_t addrCount = _wallet->Raw.WalletAllAddrs((BRWallet *) _wallet, NULL, 0);

			BRAddress addresses[addrCount];
			_wallet->Raw.WalletAllAddrs((BRWallet *) _wallet, addresses, addrCount);

			std::vector<std::string> results;
			for (int i = 0; i < addrCount; i++) {
				results.push_back(addresses[i].s);
			}
			return results;
		}

		bool Wallet::containsAddress(const std::string &address) {
			if (_wallet->IsSingleAddress) {
				return _wallet->SingleAddress == address;
			}

			return BRWalletContainsAddress((BRWallet *) _wallet, address.c_str()) != 0;
		}

		bool Wallet::addressIsUsed(const std::string &address) {

			return BRWalletAddressIsUsed((BRWallet *) _wallet, address.c_str()) != 0;
		}

		// maximum amount that can be sent from the wallet to a single address after fees
		uint64_t Wallet::WalletMaxOutputAmount(BRWallet *wallet) {
			ELATransaction *tx;
			BRUTXO *o;
			uint64_t fee, amount = 0;
			size_t i, txSize, cpfpSize = 0, inCount = 0;

			assert(wallet != NULL);
			pthread_mutex_lock(&wallet->lock);

			for (i = array_count(wallet->utxos); i > 0; i--) {
				o = &wallet->utxos[i - 1];
				tx = (ELATransaction *) BRSetGet(wallet->allTx, &o->hash);
				if (!tx || o->n >= tx->outputs.size()) continue;
				inCount++;
				amount += tx->outputs[o->n]->getAmount();

//        // size of unconfirmed, non-change inputs for child-pays-for-parent fee
//        // don't include parent tx with more than 10 inputs or 10 outputs
//        if (tx->blockHeight == TX_UNCONFIRMED && tx->inCount <= 10 && tx->outCount <= 10 &&
//            ! _BRWalletTxIsSend(wallet, tx)) cpfpSize += BRTransactionSize(tx);
			}

			txSize = 8 + BRVarIntSize(inCount) + TX_INPUT_SIZE * inCount + BRVarIntSize(2) + TX_OUTPUT_SIZE * 2;
			fee = _txFee(wallet->feePerKb, txSize + cpfpSize);
			pthread_mutex_unlock(&wallet->lock);

			return (amount > fee) ? amount - fee : 0;
		}

		uint64_t Wallet::WalletFeeForTx(BRWallet *wallet, const BRTransaction *tx) {
			uint64_t amount = 0;

			assert(tx != nullptr);
			if (tx == nullptr) {
				return amount;
			}

			ELATransaction *txn = (ELATransaction *) tx;
			pthread_mutex_lock(&wallet->lock);

			for (size_t i = 0; txn && i < txn->raw.inCount && amount != UINT64_MAX; i++) {
				ELATransaction *t = (ELATransaction *) BRSetGet(wallet->allTx, &txn->raw.inputs[i].txHash);
				uint32_t n = txn->raw.inputs[i].index;

				if (t && n < t->outputs.size()) {
					amount += t->outputs[n]->getAmount();
				} else amount = UINT64_MAX;
			}

			pthread_mutex_unlock(&wallet->lock);

			for (size_t i = 0; txn && i < txn->outputs.size() && amount != UINT64_MAX; i++) {
				amount -= txn->outputs[i]->getAmount();
			}

			return amount;
		}

		void Wallet::WalletUpdateBalance(BRWallet *wallet) {
			int isInvalid, isPending;
			uint64_t balance = 0, prevBalance = 0;
			time_t now = time(NULL);
			size_t i, j;
			ELATransaction *tx, *t;

			array_clear(wallet->utxos);
			array_clear(wallet->balanceHist);
			BRSetClear(wallet->spentOutputs);
			BRSetClear(wallet->invalidTx);
			BRSetClear(wallet->pendingTx);
			BRSetClear(wallet->usedAddrs);
			wallet->totalSent = 0;
			wallet->totalReceived = 0;

			for (i = 0; i < array_count(wallet->transactions); i++) {
				tx = (ELATransaction *) wallet->transactions[i];

				// check if any inputs are invalid or already spent
				if (tx->raw.blockHeight == TX_UNCONFIRMED) {
					for (j = 0, isInvalid = 0; !isInvalid && j < tx->raw.inCount; j++) {
						if (BRSetContains(wallet->spentOutputs, &tx->raw.inputs[j]) ||
							BRSetContains(wallet->invalidTx, &tx->raw.inputs[j].txHash))
							isInvalid = 1;
					}

					if (isInvalid) {
						BRSetAdd(wallet->invalidTx, tx);
						array_add(wallet->balanceHist, balance);
						continue;
					}
				}

				// add inputs to spent output set
				for (j = 0; j < tx->raw.inCount; j++) {
					BRSetAdd(wallet->spentOutputs, &tx->raw.inputs[j]);
				}

				// check if tx is pending
				if (tx->raw.blockHeight == TX_UNCONFIRMED) {
					isPending = (ELATransactionSize(tx) > TX_MAX_SIZE) ? 1 : 0; // check tx size is under TX_MAX_SIZE

					for (j = 0; !isPending && j < tx->outputs.size(); j++) {
						if (tx->outputs[j]->getAmount() < TX_MIN_OUTPUT_AMOUNT)
							isPending = 1; // check that no outputs are dust
					}

					for (j = 0; !isPending && j < tx->raw.inCount; j++) {
						if (tx->raw.inputs[j].sequence < UINT32_MAX - 1) isPending = 1; // check for replace-by-fee
						if (tx->raw.inputs[j].sequence < UINT32_MAX && tx->raw.lockTime < TX_MAX_LOCK_HEIGHT &&
							tx->raw.lockTime > wallet->blockHeight + 1)
							isPending = 1; // future lockTime
						if (tx->raw.inputs[j].sequence < UINT32_MAX && tx->raw.lockTime > now)
							isPending = 1; // future lockTime
						if (BRSetContains(wallet->pendingTx, &tx->raw.inputs[j].txHash))
							isPending = 1; // check for pending inputs
						// TODO: XXX handle BIP68 check lock time verify rules
					}

					if (isPending) {
						BRSetAdd(wallet->pendingTx, tx);
						array_add(wallet->balanceHist, balance);
						continue;
					}
				}

				// add outputs to UTXO set
				// TODO: don't add outputs below TX_MIN_OUTPUT_AMOUNT
				// TODO: don't add coin generation outputs < 100 blocks deep
				// NOTE: balance/UTXOs will then need to be recalculated when last block changes
				for (j = 0; tx->raw.blockHeight != TX_UNCONFIRMED && j < tx->outputs.size(); j++) {
					if (tx->outputs[j]->getRaw()->address[0] != '\0') {
						if (((ELAWallet *) wallet)->IsSingleAddress) {
							ELAWallet *elaWallet = (ELAWallet *) wallet;
							if (elaWallet->SingleAddress == std::string(tx->outputs[j]->getRaw()->address)) {
								array_add(wallet->utxos, ((BRUTXO) {tx->raw.txHash, (uint32_t) j}));
								balance += tx->outputs[j]->getAmount();
							}
						} else {
							BRSetAdd(wallet->usedAddrs, tx->outputs[j]->getRaw()->address);

							if (BRSetContains(wallet->allAddrs, tx->outputs[j]->getRaw()->address)) {
								array_add(wallet->utxos, ((BRUTXO) {tx->raw.txHash, (uint32_t) j}));
								balance += tx->outputs[j]->getAmount();
							}
						}
					}
				}

				// transaction ordering is not guaranteed, so check the entire UTXO set against the entire spent output set
				for (j = array_count(wallet->utxos); j > 0; j--) {
					if (!BRSetContains(wallet->spentOutputs, &wallet->utxos[j - 1])) continue;
					t = (ELATransaction *) BRSetGet(wallet->allTx, &wallet->utxos[j - 1].hash);
					balance -= t->outputs[wallet->utxos[j - 1].n]->getAmount();
					array_rm(wallet->utxos, j - 1);
				}

				if (prevBalance < balance) wallet->totalReceived += balance - prevBalance;
				if (balance < prevBalance) wallet->totalSent += prevBalance - balance;
				array_add(wallet->balanceHist, balance);
				prevBalance = balance;
			}

			assert(array_count(wallet->balanceHist) == array_count(wallet->transactions));
			wallet->balance = balance;
		}

		int Wallet::WalletContainsTx(BRWallet *wallet, const BRTransaction *tx) {
			int r = 0;

			ELAWallet *elaWallet = (ELAWallet *) wallet;
			const ELATransaction *txn = (const ELATransaction *) tx;

			if (!txn)
				return r;

			size_t outCount = txn->outputs.size();

			for (size_t i = 0; !r && i < outCount; i++) {
				if (elaWallet->IsSingleAddress) {
					if (elaWallet->SingleAddress == std::string(txn->outputs[i]->getRaw()->address)) {
						r = 1;
					}
				} else {
					if (BRSetContains(wallet->allAddrs, txn->outputs[i]->getRaw()->address)) {
						r = 1;
					}
				}
			}

			for (size_t i = 0; !r && i < txn->raw.inCount; i++) {
				ELATransaction *t = (ELATransaction *) BRSetGet(wallet->allTx, &txn->raw.inputs[i].txHash);
				uint32_t n = txn->raw.inputs[i].index;

				if (t == nullptr || n >= t->outputs.size()) {
					continue;
				}

				if (elaWallet->IsSingleAddress) {
					if (elaWallet->SingleAddress == std::string(t->outputs[n]->getRaw()->address)) {
						r = 1;
					}
				} else {
					if (BRSetContains(wallet->allAddrs, t->outputs[n]->getRaw()->address)) {
						r = 1;
					}
				}
			}

			//for listening addresses
			for (size_t i = 0; i < outCount; ++i) {
				if (std::find(elaWallet->ListeningAddrs.begin(), elaWallet->ListeningAddrs.end(),
							  txn->outputs[i]->getRaw()->address) != elaWallet->ListeningAddrs.end())
					r = 1;
			}

			return r;
		}

		void Wallet::WalletAddUsedAddrs(BRWallet *wallet, const BRTransaction *tx) {
			const ELATransaction *txn = (const ELATransaction *) tx;

			if (!txn)
				return;

			size_t outCount = txn->outputs.size();
			for (size_t j = 0; j < outCount; j++) {
				if (txn->outputs[j]->getRaw()->address[0] != '\0')
					BRSetAdd(wallet->usedAddrs, txn->outputs[j]->getRaw()->address);
			}
		}

		int Wallet::TransactionIsSigned(const BRTransaction *tx) {
			return true == ELATransactionIsSign((ELATransaction *) tx);
		}

		void Wallet::setApplyFreeTx(void *info, void *tx) {
			ELATransactionFree((ELATransaction *) tx);
		}

		typedef boost::weak_ptr<Wallet::Listener> WeakListener;

		void Wallet::balanceChanged(void *info, uint64_t balance) {

			WeakListener *listener = (WeakListener *) info;
			if (!listener->expired()) {
				listener->lock()->balanceChanged(balance);
			}
		}

		void Wallet::txAdded(void *info, BRTransaction *tx) {

			WeakListener *listener = (WeakListener *) info;
			if (!listener->expired()) {
				listener->lock()->onTxAdded(TransactionPtr(new Transaction((ELATransaction *) tx, false)));
			}
		}

		void Wallet::txUpdated(void *info, const UInt256 txHashes[], size_t count, uint32_t blockHeight,
							   uint32_t timestamp) {

			WeakListener *listener = (WeakListener *) info;
			if (!listener->expired()) {

				// Invoke the callback for each of txHashes.
				for (size_t i = 0; i < count; i++) {
					listener->lock()->onTxUpdated(Utils::UInt256ToString(txHashes[i]), blockHeight, timestamp);
				}
			}
		}

		void Wallet::txDeleted(void *info, UInt256 txHash, int notifyUser, int recommendRescan) {

			WeakListener *listener = (WeakListener *) info;
			if (!listener->expired()) {
				listener->lock()->onTxDeleted(Utils::UInt256ToString(txHash), static_cast<bool>(notifyUser),
											  static_cast<bool>(recommendRescan));
			}
		}

		size_t Wallet::KeyToAddress(const BRKey *key, char *addr, size_t addrLen) {
			BRKey *brKey = new BRKey;
			memcpy(brKey, key, sizeof(BRKey));

			KeyPtr keyPtr(new Key(brKey));

			std::string address = keyPtr->address();

			memset(addr, '\0', addrLen);
			strncpy(addr, address.c_str(), addrLen - 1);

			return address.size();
		}

		uint32_t Wallet::getBlockHeight() const {
			return _wallet->Raw.blockHeight;
		}

		size_t Wallet::WalletUnusedAddrs(BRWallet *wallet, BRAddress addrs[], uint32_t gapLimit, int internal) {
			ELAWallet *elaWallet = (ELAWallet *) wallet;
			if (elaWallet->IsSingleAddress) {
				if (addrs != NULL) {
					memset(addrs[0].s, 0, sizeof(addrs[0].s));
					strncpy(addrs[0].s, elaWallet->SingleAddress.c_str(), sizeof(addrs[0].s) - 1);
				}
				return 1;
			}

			BRAddress *addrChain, emptyAddress = BR_ADDRESS_NONE;
			size_t i, j = 0, count, startCount;
			uint32_t chain = (internal) ? SEQUENCE_INTERNAL_CHAIN : SEQUENCE_EXTERNAL_CHAIN;

			assert(wallet != NULL);
			assert(gapLimit > 0);
			pthread_mutex_lock(&wallet->lock);
			addrChain = (internal) ? wallet->internalChain : wallet->externalChain;
			i = count = startCount = array_count(addrChain);

			// keep only the trailing contiguous block of addresses with no transactions
			while (i > 0 && !BRSetContains(wallet->usedAddrs, &addrChain[i - 1])) i--;

			while (i + gapLimit > count) { // generate new addresses up to gapLimit
				Key key;
				BRAddress address = BR_ADDRESS_NONE;

				size_t len = BRBIP32PubKey(NULL, 0, wallet->masterPubKey, chain, count);
				CMBlock pubKey(len);
				BRBIP32PubKey(pubKey, pubKey.GetSize(), wallet->masterPubKey, chain, count);

				if (!key.setPubKey(pubKey)) break;
				if (!wallet->KeyToAddress(key.getRaw(), address.s, sizeof(BRAddress)) ||
					BRAddressEq(&address, &emptyAddress))
					break;

				array_add(addrChain, address);
				count++;
				if (BRSetContains(wallet->usedAddrs, &address)) i = count;
			}

			if (addrs && i + gapLimit <= count) {
				for (j = 0; j < gapLimit; j++) {
					addrs[j] = addrChain[i + j];
				}
			}

			// was addrChain moved to a new memory location?
			if (addrChain == (internal ? wallet->internalChain : wallet->externalChain)) {
				for (i = startCount; i < count; i++) {
					BRSetAdd(wallet->allAddrs, &addrChain[i]);
				}
			} else {
				if (internal) wallet->internalChain = addrChain;
				if (!internal) wallet->externalChain = addrChain;
				BRSetClear(wallet->allAddrs); // clear and rebuild allAddrs

				for (i = array_count(wallet->internalChain); i > 0; i--) {
					BRSetAdd(wallet->allAddrs, &wallet->internalChain[i - 1]);
				}

				for (i = array_count(wallet->externalChain); i > 0; i--) {
					BRSetAdd(wallet->allAddrs, &wallet->externalChain[i - 1]);
				}
			}

			pthread_mutex_unlock(&wallet->lock);
			return j;
		}

		uint64_t Wallet::BalanceAfterTx(BRWallet *wallet, const BRTransaction *tx) {
			uint64_t balance;

			assert(wallet != NULL);
			assert(tx != NULL && wallet->TransactionIsSigned(tx));
			pthread_mutex_lock(&wallet->lock);
			balance = wallet->balance;

			for (size_t i = array_count(wallet->transactions); tx && i > 0; i--) {
				if (!BRTransactionEq(tx, wallet->transactions[i - 1])) continue;

				balance = wallet->balanceHist[i - 1];
				break;
			}

			pthread_mutex_unlock(&wallet->lock);
			return balance;
		}

		size_t Wallet::WalletAllAddrs(BRWallet *wallet, BRAddress *addrs, size_t addrsCount) {
			ELAWallet *elaWallet = (ELAWallet *) wallet;
			if (elaWallet->IsSingleAddress) {
				if (addrs != NULL && addrsCount > 0) {
					memset(addrs[0].s, 0, sizeof(addrs[0].s));
					strncpy(addrs[0].s, elaWallet->SingleAddress.c_str(), sizeof(addrs[0].s) - 1);
				}
				return 1;
			}
			return BRWalletAllAddrs(wallet, addrs, addrsCount);
		}

		void Wallet::signTransaction(const boost::shared_ptr<Transaction> &transaction, int forkId,
									 const std::string &payPassword) {
			ParamChecker::checkCondition(transaction.get() == nullptr, Error::InvalidArgument, "Sign null tx");
			_subAccount->SignTransaction(transaction, _wallet, payPassword);
		}

	}
}


text:
/*
 * Copyright 2017, Justin Carpentier, LAAS-CNRS
 *
 * This file is part of eigenpy.
 * eigenpy is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * eigenpy 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 eigenpy.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __eigenpy_basic_preconditioners_hpp__
#define __eigenpy_basic_preconditioners_hpp__

#include "eigenpy/fwd.hpp"
#include <Eigen/IterativeLinearSolvers>

namespace eigenpy
{

  namespace bp = boost::python;

  template<typename Preconditioner>
  struct PreconditionerBaseVisitor
  : public bp::def_visitor< PreconditionerBaseVisitor<Preconditioner> >
  {
    typedef Eigen::MatrixXd MatrixType;
    typedef Eigen::VectorXd VectorType;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      cl
      .def(bp::init<>("Default constructor"))
      .def(bp::init<MatrixType>(bp::arg("A"),"Initialize the preconditioner with matrix A for further Az=b solving."))
#if EIGEN_VERSION_AT_LEAST(3,3,0)
      .def("info",&Preconditioner::info,
           "Returns success if the Preconditioner has been well initialized.")
#endif
      .def("solve",&solve,bp::arg("b"),
           "Returns the solution A * z = b where the preconditioner is an estimate of A^-1.")

      .def("compute",&Preconditioner::template compute<MatrixType>,bp::arg("mat"),
           "Initialize the preconditioner from the matrix value.",
           bp::return_value_policy<bp::reference_existing_object>())
      .def("factorize",&Preconditioner::template factorize<MatrixType>,bp::arg("mat"),
           "Initialize the preconditioner from the matrix value, i.e factorize the mat given as input to approximate its inverse.",
           bp::return_value_policy<bp::reference_existing_object>())
      ;

    }

  private:

    static VectorType solve(Preconditioner & self, const VectorType & b)
    {
      return self.solve(b);
    }

  };

  template<typename Scalar>
  struct DiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar> >
  {
    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
    typedef Eigen::DiagonalPreconditioner<Scalar> Preconditioner;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      cl
      .def(PreconditionerBaseVisitor<Preconditioner>())
      .def("rows",&Preconditioner::rows,"Returns the number of rows in the preconditioner.")
      .def("cols",&Preconditioner::cols,"Returns the number of cols in the preconditioner.")
      ;

    }

    static void expose()
    {
      bp::class_<Preconditioner>("DiagonalPreconditioner",
                                 "A preconditioner based on the digonal entrie.\n"
                                 "This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix.",
                                 bp::no_init)
      ;

    }
  };

#if EIGEN_VERSION_AT_LEAST(3,3,5)
  template<typename Scalar>
  struct LeastSquareDiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::LeastSquareDiagonalPreconditioner<Scalar> >
  {
    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
    typedef Eigen::LeastSquareDiagonalPreconditioner<Scalar> Preconditioner;

    template<class PyClass>
    void visit(PyClass&) const
    {
    }

    static void expose()
    {
      bp::class_<Preconditioner>("LeastSquareDiagonalPreconditioner",
                                 "Jacobi preconditioner for LeastSquaresConjugateGradient.\n"
                                 "his class allows to approximately solve for A' A x  = A' b problems assuming A' A is a diagonal matrix.",
                                 bp::no_init)
      .def(DiagonalPreconditionerVisitor<Scalar>())
      ;

    }
  };
#endif

  struct IdentityPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::IdentityPreconditioner >
  {
    typedef Eigen::IdentityPreconditioner Preconditioner;

    template<class PyClass>
    void visit(PyClass&) const
    {
    }

    static void expose()
    {
      bp::class_<Preconditioner>("IdentityPreconditioner",
                                 bp::no_init)
      .def(PreconditionerBaseVisitor<Preconditioner>())
      ;

    }
  };

} // namespace eigenpy

#endif // ifndef __eigenpy_basic_preconditioners_hpp__

ext: hpp

max_stars_repo_name: seanyen/eigenpy

max_issues_repo_name: seanyen/eigenpy

max_forks_repo_name: seanyen/eigenpy


text:
#ifndef OSRM_UPDATER_CSV_FILE_PARSER_HPP
#define OSRM_UPDATER_CSV_FILE_PARSER_HPP

#include "updater/source.hpp"

#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/log.hpp"

#include <tbb/parallel_for.h>
#include <tbb/parallel_sort.h>
#include <tbb/spin_mutex.h>

#include <boost/exception/diagnostic_information.hpp>
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

#include <vector>

namespace osrm
{
namespace updater
{

// Functor to parse a list of CSV files using "key,value,comment" grammar.
// Key and Value structures must be a model of Random Access Sequence.
// Also the Value structure must have source member that will be filled
// with the corresponding file index in the CSV filenames vector.
template <typename Key, typename Value> struct CSVFilesParser
{
    using Iterator = boost::iostreams::mapped_file_source::iterator;
    using KeyRule = boost::spirit::qi::rule<Iterator, Key()>;
    using ValueRule = boost::spirit::qi::rule<Iterator, Value()>;

    CSVFilesParser(std::size_t start_index, const KeyRule &key_rule, const ValueRule &value_rule)
        : start_index(start_index), key_rule(key_rule), value_rule(value_rule)
    {
    }

    // Operator returns a lambda function that maps input Key to boost::optional<Value>.
    auto operator()(const std::vector<std::string> &csv_filenames) const
    {
        try
        {
            tbb::spin_mutex mutex;
            std::vector<std::pair<Key, Value>> lookup;
            tbb::parallel_for(std::size_t{0},
                              csv_filenames.size(),
                              [&](const std::size_t idx) {
                                  auto local = ParseCSVFile(csv_filenames[idx], start_index + idx);

                                  { // Merge local CSV results into a flat global vector
                                      tbb::spin_mutex::scoped_lock _{mutex};
                                      lookup.insert(end(lookup),
                                                    std::make_move_iterator(begin(local)),
                                                    std::make_move_iterator(end(local)));
                                  }
                              });

            // With flattened map-ish view of all the files, make a stable sort on key and source
            // and unique them on key to keep only the value with the largest file index
            // and the largest line number in a file.
            // The operands order is swapped to make descending ordering on (key, source)
            tbb::parallel_sort(begin(lookup), end(lookup), [](const auto &lhs, const auto &rhs) {
                return std::tie(rhs.first, rhs.second.source) <
                       std::tie(lhs.first, lhs.second.source);
            });

            // Unique only on key to take the source precedence into account and remove duplicates.
            const auto it =
                std::unique(begin(lookup), end(lookup), [](const auto &lhs, const auto &rhs) {
                    return lhs.first == rhs.first;
                });
            lookup.erase(it, end(lookup));

            util::Log() << "In total loaded " << csv_filenames.size() << " file(s) with a total of "
                        << lookup.size() << " unique values";

            return LookupTable<Key, Value>{lookup};
        }
        catch (const tbb::captured_exception &e)
        {
            throw util::exception(e.what() + SOURCE_REF);
        }
    }

  private:
    // Parse a single CSV file and return result as a vector<Key, Value>
    auto ParseCSVFile(const std::string &filename, std::size_t file_id) const
    {
        namespace qi = boost::spirit::qi;

        std::vector<std::pair<Key, Value>> result;
        try
        {
            if (boost::filesystem::file_size(filename) == 0)
                return result;

            boost::iostreams::mapped_file_source mmap(filename);
            auto first = mmap.begin(), last = mmap.end();

            BOOST_ASSERT(file_id <= std::numeric_limits<std::uint8_t>::max());
            ValueRule value_source =
                value_rule[qi::_val = qi::_1, bind(&Value::source, qi::_val) = file_id];
            qi::rule<Iterator, std::pair<Key, Value>()> csv_line =
                (key_rule >> ',' >> value_source) >> -(',' >> *(qi::char_ - qi::eol));
            const auto ok = qi::parse(first, last, -(csv_line % qi::eol) >> *qi::eol, result);

            if (!ok || first != last)
            {
                auto begin_of_line = first - 1;
                while (begin_of_line >= mmap.begin() && *begin_of_line != '\n')
                    --begin_of_line;
                auto line_number = std::count(mmap.begin(), first, '\n') + 1;
                const auto message = boost::format("CSV file %1% malformed on line %2%:\n %3%\n") %
                                     filename % std::to_string(line_number) %
                                     std::string(begin_of_line + 1, std::find(first, last, '\n'));
                throw util::exception(message.str() + SOURCE_REF);
            }

            util::Log() << "Loaded " << filename << " with " << result.size() << "values";

            return std::move(result);
        }
        catch (const boost::exception &e)
        {
            const auto message = boost::format("exception in loading %1%:\n %2%") % filename %
                                 boost::diagnostic_information(e);
            throw util::exception(message.str() + SOURCE_REF);
        }
    }

    const std::size_t start_index;
    const KeyRule key_rule;
    const ValueRule value_rule;
};
}
}

#endif

max_issues_repo_name: serarca/osrm-backend

max_forks_repo_name: serarca/osrm-backend


text:
#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/program_options.hpp>

#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkImageRegionIterator.h>
#include <itkImageRegionConstIterator.h>
#include <itkMaskImageFilter.h>
#include <itkBinaryImageToLabelMapFilter.h>
#include <itkLabelStatisticsImageFilter.h>

int main(int argc,char **argv)
{
    std::string     labelTableFile, labelImageFile, outImageFile, fileToModify;
    bool modifyExisting;

    boost::program_options::options_description optionsDescription("create an image from a label image and a lable table.");
    optionsDescription.add_options()
	("help,h", "display help message")
	("table,t", boost::program_options::value< std::string >(&labelTableFile), "label table with two columns: labels and corresponding pixel values to be assigned to the output image.")
	("labelImage,l", boost::program_options::value< std::string >(&labelImageFile), "input label image file from which the regions matching the labels in the table will be extracted"
	 "New pixel values will be put to only these extracted regions.")
	("outputImage,o",boost::program_options::value< std::string >(&outImageFile), "Output image")
	("fileToModify,m",boost::program_options::value< std::string >(&fileToModify), " The image that is to be modified to produce output image."
	 " If not provided, creates a new image with zero value everywhere"
	 " and then updates the extracted regions.")
	;

    boost::program_options::variables_map options;
    boost::program_options::store(boost::program_options::parse_command_line(argc,argv,optionsDescription),options);
    boost::program_options::notify(options);

//If help is asked!
    if(options.count("help")) {
	std::cout<<optionsDescription<<std::endl;
	return EXIT_SUCCESS;
    }

//Confirm all the options required are given.
    if(!options.count("table") || !options.count("labelImage")
       || !options.count("outputImage")
	) {
	std::cerr<<"invalid options! run with --help or -h to see the proper options."<<std::endl;
	return EXIT_FAILURE;
    }

// Check if file to be modified is given or not.
    if(!options.count("fileToModify"))
	modifyExisting = false;
    else
	modifyExisting = true;
    typedef itk::Image<int, 3> LabelImageType;
    typedef itk::Image<float, 3> OutImageType;

// Open label table file for reading
    std::ifstream labelTable(labelTableFile.c_str(),std::ios::in);
    if (!labelTable.is_open()) {
	std::cerr<<"could not open file: "<<labelTableFile<<std::endl;
	return EXIT_FAILURE;
    }

// Read first line of the table and check if it is in the desired format i.e. labels newValues
    {
	std::string line;
	std::getline(labelTable, line);
	std::istringstream is(line);
	std::string checkString;
	is >> checkString;
	if(checkString.compare("labels")) {
	    std::cout<<"incorrect table format. 1st col- labels; 2nd col- newValues"<<std::endl<<"The first word must be: labels"<<std::endl;
	    return EXIT_FAILURE;
	}
	is >> checkString;
	if (checkString.compare("newValues")) {
	    std::cout<<"incorrect table format. 1st col- labels; 2nd col- newValues"<<std::endl<<"The second word must be: newValues"<<std::endl;
	    return EXIT_FAILURE;
	}
    }

// From the second line, read the values and put it into a map.
    typedef std::map< LabelImageType::PixelType, OutImageType::PixelType > LabelWithValueType;
    typedef std::pair< LabelImageType::PixelType, OutImageType::PixelType > LabelValuePairType;
    typedef LabelWithValueType::iterator LabelWithValueIteratorType;

    LabelWithValueType labelWithValue;
    while(!labelTable.eof()) {
	std::string line;
	std::getline(labelTable, line);
	std::istringstream is(line);
	LabelImageType::PixelType label;
	is >> label;
	OutImageType::PixelType outValue;
	is >> outValue;
	labelWithValue.insert(LabelValuePairType(label, outValue));
    }
    labelTable.close();

    for (LabelWithValueIteratorType labelWithValueIt = labelWithValue.begin(); labelWithValueIt != labelWithValue.end(); ++labelWithValueIt) {
	std::cout<<labelWithValueIt->first<<" ** "<<labelWithValueIt->second<<std::endl;
    }

// Read label image
    typedef itk::ImageFileReader< LabelImageType > LabelImageReaderType;
    LabelImageReaderType::Pointer labelImageReader = LabelImageReaderType::New();
    labelImageReader->SetFileName(labelImageFile);
    labelImageReader->Update();
    LabelImageType::Pointer labelImage = labelImageReader->GetOutput();

// Output image.
    OutImageType::Pointer outImage = OutImageType::New();
    if (modifyExisting) {
	typedef itk::ImageFileReader< OutImageType > OutImageReaderType;
	OutImageReaderType::Pointer outImageReader = OutImageReaderType::New();
	outImageReader->SetFileName(fileToModify);
	outImageReader->Update();
	outImage = outImageReader->GetOutput();
    } else { // If not modifying create new image of the same size as label image and fill it with zero.
	outImage->SetRegions(labelImage->GetLargestPossibleRegion());
	outImage->CopyInformation(labelImage);
	outImage->Allocate();
	outImage->FillBuffer(0.);
    }

    //L:labelImage A:outImage  out(I):out value for the corresponding label I read from the table.
    //if ( L(x) != 0 ) then A(x) = out(L(x)) or just A(x) = out(L(x)) without if; when you want for label 0 also.
    typedef itk::ImageRegionConstIterator< LabelImageType > LabelIteratorType;
    typedef itk::ImageRegionIterator< OutImageType > ValueIteratorType;
    LabelIteratorType labelIt(labelImage, labelImage->GetLargestPossibleRegion());
    ValueIteratorType outIt(outImage, outImage->GetLargestPossibleRegion());
    labelIt.GoToBegin();
    outIt.GoToBegin();
    while(!labelIt.IsAtEnd())
    {
	LabelImageType::PixelType currLabel = labelIt.Get();
	//std::cout<<"LabelImage[x]="<<currLabel<<std::endl;
	// if(currLabel) //for all non-zero labels
	// {
	for (LabelWithValueIteratorType labelWithValueIt = labelWithValue.begin(); labelWithValueIt != labelWithValue.end(); ++labelWithValueIt)
	{
	    //std::cout<<"LabelImage[x]="<<currLabel<<",  labelTable[current]="<<labelWithValueIt->first<<std::endl;
	    if (currLabel == labelWithValueIt->first)
	    {
		//std::cout<<"LabelImage[x]="<<currLabel<<",  labelTable[current]="<<labelWithValueIt->first<<std::endl;
		outIt.Set(labelWithValueIt->second);
		break;
	    }
	}
	//}
	++labelIt;
	++outIt;
    }

// //Label Statistics Filter to write to only those labels which are present in the input label image.
// typedef itk::BinaryImageToLabelMapFilter< LabelImageType > ImageToLabelMapFilterType;
// ImageToLabelMapFilterType::Pointer labelMap = ImageToLabelMapFilterType::New();
// labelMap->SetInput(labelImage);
// labelMap->Update();
// std::cout<<"There are originally "<< labelMap->GetOutput()->GetNumberOfLabelObjects() << " objects"<<std::endl;

// //Label Statistics Filter to compute mean of each regions:
// typedef itk::LabelStatisticsImageFilter< OutImageType, LabelImageType > LabelStatsFilterType;
// LabelStatsFilterType::Pointer labelStats = LabelStatsFilterType::New();
// labelStats->SetLabelInput( labelImage);
// labelStats->SetInput(outImage);
// labelStats->Update();
// std::cout << "Number of labels in the input label image: " << labelStats->GetNumberOfLabels() << std::endl;

// typedef itk::MaskImageFilter<OutImageType, LabelImageType, OutImageType> MaskImageFilterType;
// MaskImageFilterType::Pointer maskImageFilter = MaskImageFilterType::New();
// maskImageFilter->SetMaskImage(labelImage);
// for (LabelWithValueIteratorType labelWithValueIt = labelWithValue.begin(); labelWithValueIt != labelWithValue.end(); ++labelWithValueIt)
// {
// 	LabelImageType::PixelType label = labelWithValueIt->first;
// 	OutImageType::PixelType val = labelWithValueIt->second;
// 	std::cout<<"Testing for label "<<label<<" with value "<<val<<std::endl;
// 	if(labelStats->HasLabel(label))//if(labelMap->GetOutput()->HasLabel(label))
// 	{
// 	    maskImageFilter->SetInput(outImage);
// 	    //if (pixel_from_mask_image != masking_value)     pixel_output_image = pixel_input_image
// 	    //else pixel_output_image = outside_value
// 	    maskImageFilter->SetMaskingValue(label);
// 	    maskImageFilter->SetOutsideValue(val);
// 	    maskImageFilter->Update();
// 	    outImage = maskImageFilter->GetOutput();
// 	    outImage->DisconnectPipeline();
// 	}
// 	else {
// 	    std::cout<<" Label Id "<<label<<" not present in the label image"<<std::endl;
// 	}
// }

// Write the out output.
    typedef itk::ImageFileWriter< OutImageType > ValueImageWriterType;
    ValueImageWriterType::Pointer outImageWriter = ValueImageWriterType::New();
    outImageWriter->SetFileName(outImageFile);
    outImageWriter->SetInput(outImage);
    outImageWriter->Update();
    return EXIT_SUCCESS;
}

ext: cxx

max_stars_repo_name: richardbeare/simul-atrophy

max_issues_repo_name: richardbeare/simul-atrophy

max_forks_repo_name: richardbeare/simul-atrophy


text:
//
// $Id$
//
//
// Original author: Darren Kessner <darren@proteowizard.org>
//
// Copyright 2007 Spielberg Family Center for Applied Proteomics
//   Cedars-Sinai Medical Center, Los Angeles, California  90048
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef _PARAMTYPES_HPP_
#define _PARAMTYPES_HPP_

#include "pwiz/utility/misc/Export.hpp"
#include "pwiz/utility/misc/optimized_lexical_cast.hpp"
#include "cv.hpp"
#include <iosfwd>
#include <vector>
#include <boost/shared_ptr.hpp>

namespace pwiz {
namespace data {

using namespace pwiz::cv;

/// represents a tag-value pair, where the tag comes from the controlled vocabulary
struct PWIZ_API_DECL CVParam
{
    CVID cvid;
    std::string value;
    CVID units;

    CVParam(CVID _cvid, float _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(boost::lexical_cast<std::string>(_value)),
        units(_units)
    {}

    CVParam(CVID _cvid, double _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(boost::lexical_cast<std::string>(_value)),
        units(_units)
    {}

    CVParam(CVID _cvid, int _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(boost::lexical_cast<std::string>(_value)),
        units(_units)
    {}

    CVParam(CVID _cvid, long _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(boost::lexical_cast<std::string>(_value)),
        units(_units)
    {}

    CVParam(CVID _cvid, unsigned int _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(boost::lexical_cast<std::string>(_value)),
        units(_units)
    {}

    CVParam(CVID _cvid, unsigned long _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(boost::lexical_cast<std::string>(_value)),
        units(_units)
    {}

    CVParam(CVID _cvid, std::string _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(_value),
        units(_units)
    {}

    CVParam(CVID _cvid, const char* _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid),
        value(_value),
        units(_units)
    {}

    /// special case for bool (no lexical_cast)
    CVParam(CVID _cvid, bool _value, CVID _units = CVID_Unknown)
    :   cvid(_cvid), value(_value ? "true" : "false"), units(_units)
    {}

    /// constructor for non-valued CVParams
    CVParam(CVID _cvid = CVID_Unknown)
    :   cvid(_cvid), units(CVID_Unknown)
    {}

    ~CVParam();

    /// templated value access with type conversion
    template<typename value_type>
    value_type valueAs() const
    {
        return !value.empty() ? boost::lexical_cast<value_type>(value)
                             : boost::lexical_cast<value_type>(0);
    }

    /// convenience function to return string for the cvid
    std::string name() const;

    /// convenience function to return string for the units
    std::string unitsName() const;

    /// convenience function to return time in seconds (throws if units not a time unit)
    double timeInSeconds() const;

    /// convenience function to return value without scientific notation (throws if not a double)
    std::string valueFixedNotation() const;

    /// equality operator
    bool operator==(const CVParam& that) const
    {
        return that.cvid==cvid && that.value==value && that.units==units;
    }

    /// inequality operator
    bool operator!=(const CVParam& that) const
    {
        return !operator==(that);
    }

    bool empty() const {return cvid==CVID_Unknown && value.empty() && units==CVID_Unknown;}
};

/// functor for finding CVParam with specified exact CVID in a collection of CVParams:
///
/// vector<CVParam>::const_iterator it =
///     find_if(params.begin(), params.end(), CVParamIs(MS_software));
///
struct PWIZ_API_DECL CVParamIs
{
    CVParamIs(CVID cvid) : cvid_(cvid) {}
    bool operator()(const CVParam& param) const {return param.cvid == cvid_;}
    CVID cvid_;
};

/// functor for finding children of a specified CVID in a collection of CVParams:
///
/// vector<CVParam>::const_iterator it =
///     find_if(params.begin(), params.end(), CVParamIsChildOf(MS_software));
///
struct PWIZ_API_DECL CVParamIsChildOf
{
    CVParamIsChildOf(CVID cvid) : cvid_(cvid) {}
    bool operator()(const CVParam& param) const {return cvIsA(param.cvid, cvid_);}
    CVID cvid_;
};

/// special case for bool (no lexical_cast)
/// (this has to be outside the class for gcc 3.4, inline for msvc)
template<>
inline bool CVParam::valueAs<bool>() const
{
    return value == "true";
}

PWIZ_API_DECL std::ostream& operator<<(std::ostream& os, const CVParam& param);

/// Uncontrolled user parameters (essentially allowing free text). Before using these, one should verify whether there is an appropriate CV term available, and if so, use the CV term instead
struct PWIZ_API_DECL UserParam
{
    /// the name for the parameter.
    std::string name;

    /// the value for the parameter, where appropriate.
    std::string value;

    /// the datatype of the parameter, where appropriate (e.g.: xsd:float).
    std::string type;

    /// an optional CV parameter for the unit term associated with the value, if any (e.g. MS_electron_volt).
    CVID units;

    UserParam(const std::string& _name = "",
              const std::string& _value = "",
              const std::string& _type = "",
              CVID _units = CVID_Unknown);

    ~UserParam();

    UserParam(const UserParam& other);
    UserParam& operator=(const UserParam& rhs);

    /// convenience function to return time in seconds (throws if units not a time unit)
    double timeInSeconds() const;

    /// Templated value access with type conversion
    template<typename value_type>
    value_type valueAs() const
    {
        return !value.empty() ? boost::lexical_cast<value_type>(value)
                              : boost::lexical_cast<value_type>(0);
    }

    /// returns true iff name, value, type, and units are all empty
    bool empty() const;

    /// returns true iff name, value, type, and units are all pairwise equal
    bool operator==(const UserParam& that) const;

    /// returns !(this==that)
    bool operator!=(const UserParam& that) const;
};

// Special case for bool (outside the class for gcc 3.4, and inline for msvc)
template<>
inline bool UserParam::valueAs<bool>() const
{
    return value == "true";
}

struct ParamGroup;
typedef boost::shared_ptr<ParamGroup> ParamGroupPtr;

/// The base class for elements that may contain cvParams, userParams, or paramGroup references
struct PWIZ_API_DECL ParamContainer
{
    /// a collection of references to ParamGroups
    std::vector<ParamGroupPtr> paramGroupPtrs;

    /// a collection of controlled vocabulary terms
    std::vector<CVParam> cvParams;

    /// a collection of uncontrolled user terms
    std::vector<UserParam> userParams;

    /// finds cvid in the container:
    /// - returns first CVParam result such that (result.cvid == cvid);
    /// - if not found, returns CVParam(CVID_Unknown)
    /// - recursive: looks into paramGroupPtrs
    CVParam cvParam(CVID cvid) const;

    /// finds child of cvid in the container:
    /// - returns first CVParam result such that (result.cvid is_a cvid);
    /// - if not found, CVParam(CVID_Unknown)
    /// - recursive: looks into paramGroupPtrs
    CVParam cvParamChild(CVID cvid) const;

    /// finds cvid in the container:
    /// - returns first CVParam result's value such that (result.cvid == cvid);
    /// - if not found, returns the given default value
    /// - recursive: looks into paramGroupPtrs
    template<typename ValueT>
    ValueT cvParamValueOrDefault(CVID cvid, ValueT defaultValue) const
    {
        CVParam p = cvParam(cvid);
        return p.empty() ? defaultValue : p.valueAs<ValueT>();
    }

    /// finds child of cvid in the container:
    /// - returns first CVParam result's value such that (result.cvid is_a cvid);
    /// - if not found, returns the given default value
    /// - recursive: looks into paramGroupPtrs
    template<typename ValueT>
    CVParam cvParamChildValueOrDefault(CVID cvid, ValueT defaultValue) const
    {
        CVParam p = cvParamChild(cvid);
        return p.empty() ? defaultValue : p.valueAs<ValueT>();
    }

    /// finds all children of cvid in the container:
    /// - returns all CVParam results such that (result.cvid is_a cvid);
    /// - if not found, empty vector
    /// - recursive: looks into paramGroupPtrs
    std::vector<CVParam> cvParamChildren(CVID cvid) const;

    /// returns true iff cvParams contains exact cvid (recursive)
    bool hasCVParam(CVID cvid) const;

    /// returns true iff cvParams contains a child (is_a) of cvid (recursive)
    bool hasCVParamChild(CVID cvid) const;

    /// finds UserParam with specified name
    /// - returns UserParam() if name not found
    /// - not recursive: looks only at local userParams
    UserParam userParam(const std::string&) const;

    /// set/add a CVParam (not recursive)
    void set(CVID cvid, const std::string& value = "", CVID units = CVID_Unknown);

    /// set/add a CVParam (not recursive)
    void set(CVID cvid, double value, CVID units = CVID_Unknown);

    /// set/add a CVParam (not recursive)
    void set(CVID cvid, int value, CVID units = CVID_Unknown);

    /// set/add a CVParam (not recursive)
    template <typename value_type>
    void set(CVID cvid, value_type value, CVID units = CVID_Unknown)
    {
        set(cvid, boost::lexical_cast<std::string>(value), units);
    }

    /// returns true iff the element contains no params or param groups
    bool empty() const;

    /// clears the collections
    void clear();

    /// returns true iff this and that have the exact same cvParams and userParams
    /// - recursive: looks into paramGroupPtrs
    bool operator==(const ParamContainer& that) const;

    /// returns !(this==that)
    bool operator!=(const ParamContainer& that) const;
};

/// special case for bool (outside the class for gcc 3.4, and inline for msvc)
template<>
inline void ParamContainer::set<bool>(CVID cvid, bool value, CVID units)
{
    set(cvid, (value ? "true" : "false"), units);
}

/// A collection of CVParam and UserParam elements that can be referenced from elsewhere in this mzML document by using the 'paramGroupRef' element in that location to reference the 'id' attribute value of this element.
struct PWIZ_API_DECL ParamGroup : public ParamContainer
{
    /// the identifier with which to reference this ReferenceableParamGroup.
    std::string id;

    ParamGroup(const std::string& _id = "");

    /// returns true iff the element contains no params or param groups
    bool empty() const;
};

} // namespace data
} // namespace pwiz

#endif // _PARAMTYPES_HPP_

max_stars_repo_name: toppic-suite/topmsv

max_issues_repo_name: toppic-suite/topmsv

max_forks_repo_name: toppic-suite/topmsv


text:
//// Copyright (c) 2018 Silvio Mayolo
//// See LICENSE.txt for licensing details

#include "Dump.hpp"
#include "Parents.hpp"
#include <boost/variant.hpp>
#include <list>

struct DebugPrimVisitor : boost::static_visitor<std::string> {

    std::string operator()(boost::blank) const {
        return "";
    }

    std::string operator()(Number n) const {
        return "#(" + n.asString() + ")";
    }

    std::string operator()(std::string str) const {
        return "$(" + str + ")";
    }

    std::string operator()(Symbolic sym) const {
        return "'(" + Symbols::get()[sym] + ")";
    }

    std::string operator()(StreamPtr) const {
        return "StreamPtr";
    }

    std::string operator()(ProcessPtr) const {
        return "ProcessPtr";
    }

    std::string operator()(Method) const {
        return "Method";
    }

    std::string operator()(StatePtr) const {
        return "StatePtr";
    }

};

std::string toStringInfo(ObjectPtr obj) {
    ObjectPtr value = objectGet(obj, Symbols::get()["toString"]);
    if (value == nullptr) {
        return "";
    } else if (std::string* curr = boost::get<std::string>(&value->prim())) {
        return *curr;
    }
    return "";
}

std::ostream& operator <<(std::ostream& out, const DebugObject& obj) {
    if (obj.impl == nullptr) {
        out << "nullptr";
        return out;
    }
    // First, we know we can safely print the pointer's numerical value.
    out << obj.impl.get();
    // Get prim info
    std::string prim = boost::apply_visitor(DebugPrimVisitor(), obj.impl->prim());
    // Get toString info
    std::string str = toStringInfo(obj.impl);
    // Print everything
    if (prim != "")
        out << "[" << prim << "]";
    else if (str != "")
        out << "[" << str << "]";
    // Finish.
    return out;
}

std::ostream& operator <<(std::ostream& out, const DebugDetailObject& obj) {
    if (obj.impl == nullptr) {
        out << "nullptr";
        return out;
    }
    out << DebugObject{obj.impl} << std::endl;
    out << " Direct:" << std::endl;
    for (Symbolic key : obj.impl->directKeys()) {
        out << "  " << Symbols::get()[key] << ": "
            << DebugObject{ (*obj.impl)[key] } << std::endl;
    }
    out << " Indirect:" << std::endl;
    ObjectPtr parent = (*obj.impl)[Symbols::parent()];
    if ((parent != nullptr) && (parent != obj.impl)) {
        for (Symbolic key : keys(parent)) {
            out << "  " << Symbols::get()[key] << ": "
                << DebugObject{ objectGet(obj.impl, key) } << std::endl;
        }
    }
    return out;
}

void dumpStack(std::ostream& out, std::stack<ObjectPtr>& stack) {
    if (stack.empty())
        return;
    auto value = stack.top();
    stack.pop();
    dumpStack(out, stack);
    out << DebugObject{ value } << " ";
    stack.push(value);
}

std::ostream& operator <<(std::ostream& out, const DebugStackObject& obj) {
    if (obj.impl.empty())
        return out;
    auto value = obj.impl.top();
    obj.impl.pop();
    dumpStack(out, obj.impl);
    out << DebugObject { value };
    return out;
}

void dumpBT(std::ostream& out, NodePtr<BacktraceFrame> frame) {
    if (frame == nullptr)
        return;
    auto value = frame->get();
    out << " " << std::get<1>(value) << "(" << std::get<0>(value) << ")";
    dumpBT(out, popNode(frame));
}

void dumpEverything(std::ostream& out, VMState& vm) {

    // Stacks are printed from bottom to top, so the rightmost element
    // is the top stack element

    out << "%ptr  : " <<      DebugObject{ vm.trans.ptr } << std::endl;
    out << "%slf  : " <<      DebugObject{ vm.trans.slf } << std::endl;
    out << "%ret  : " <<      DebugObject{ vm.trans.ret } << std::endl;

    out << "%lex  : " << DebugStackObject{ vm.state.lex  } << std::endl;
    out << "%dyn  : " << DebugStackObject{ vm.state.dyn  } << std::endl;
    out << "%arg  : " << DebugStackObject{ vm.state.arg  } << std::endl;
    out << "%sto  : " << DebugStackObject{ vm.state.sto  } << std::endl;
    out << "%hand : " << DebugStackObject{ vm.state.hand } << std::endl;

    out << "%err0 : " << vm.trans.err0 << std::endl;
    out << "%err1 : " << vm.trans.err1 << std::endl;

    out << "%sym  : " << Symbols::get()[vm.trans.sym] << std::endl;
    out << "%num0 : " << vm.trans.num0.asString() << std::endl;
    out << "%num1 : " << vm.trans.num1.asString() << std::endl;

    out << "%str0 : " << vm.trans.str0 << std::endl;
    out << "%str1 : " << vm.trans.str1 << std::endl;

    out << "%flag : " << vm.trans.flag << std::endl;
    out << "%trace:";
    dumpBT(out, pushNode(vm.state.trace, std::make_tuple(vm.state.line, vm.state.file)));
    out << std::endl;

}

ext: cpp

max_stars_repo_name: Mercerenies/latitude

max_issues_repo_name: Mercerenies/latitude

max_forks_repo_name: Mercerenies/proto-lang


text:
#pragma once

#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/uuid/sha1.hpp>

namespace websocket{namespace detail{

    inline std::string generate_sec_websocket_key(){
        srand (time(NULL));
        int16_t ran = rand() % 10 + 1;
        char *p= reinterpret_cast<char *>(&ran);

        typedef boost::archive::iterators::base64_from_binary<boost::archive::iterators::transform_width<char *, 6, 8>> base64_iterator;
        base64_iterator base64_begin(p);
        base64_iterator base64_end(p+16);
        std::stringstream ss;
        copy(base64_begin, base64_end, std::ostream_iterator<char>(ss));
        ss << "==";
        return ss.str();
    }

    inline std::string generate_sec_websocket_accept(const std::string &key){
        //append 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
        auto tmp1 = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        boost::uuids::detail::sha1 sha1;
        sha1.process_bytes(tmp1.c_str(), tmp1.size());
        uint32_t sha1_result[5];
        sha1.get_digest(sha1_result);

        char *sha1_bytes = new char[20];
        for (size_t i = 0; i < 5; ++i){
            auto p_start = reinterpret_cast<char *>(sha1_result);
            sha1_bytes[i*4] = p_start[i*4 + 3];
            sha1_bytes[i*4+1] = p_start[i*4+2];
            sha1_bytes[i*4+2] = p_start[i*4+1];
            sha1_bytes[i*4+3] = p_start[i*4];
        }

        //base64 encode
        typedef boost::archive::iterators::base64_from_binary<boost::archive::iterators::transform_width<char *, 6, 8>> base64_iterator;
        base64_iterator base64_begin(sha1_bytes);
        base64_iterator base64_end(sha1_bytes+20);
        std::stringstream ss;
        copy(base64_begin, base64_end, std::ostream_iterator<char>(ss));
        ss << "=";
        delete[] sha1_bytes;
        assert(ss.str().size() == 28);
        return ss.str();
    }

    inline uint16_t get_close_code(const std::string &data){
        if (data.size() < 2){
            return uint16_t(1005);
        }else{
            uint16_t code;
            code = uint8_t(data[0]) << 8;
            code += uint8_t(data[1]);

            return code;
        }
    }

}}

max_stars_repo_name: Matazure/websocket-cpp

max_issues_repo_name: Matazure/websocket-cpp

max_forks_repo_name: Matazure/websocket-cpp


text:
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this
 *file except in compliance with the License. You may obtain a copy of the
 *License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file udm_config.hpp
 \brief
 \author  Hongxin WANG, BUPT
 \date 2021
 \email: contact@openairinterface.org
 */

#ifndef _UDM_CONFIG_H_
#define _UDM_CONFIG_H_

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <libconfig.h++>
#include <mutex>
#include <string>
#include <vector>

#include "udm_config.hpp"

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

#define UDM_CONFIG_STRING_UDM_CONFIG "UDM"
#define UDM_CONFIG_STRING_PID_DIRECTORY "PID_DIRECTORY"
#define UDM_CONFIG_STRING_INSTANCE_ID "INSTANCE_ID"
#define UDM_CONFIG_STRING_UDM_NAME "UDM_NAME"

#define UDM_CONFIG_STRING_INTERFACES "INTERFACES"
#define UDM_CONFIG_STRING_INTERFACE_SBI_UDM "SBI"
#define UDM_CONFIG_STRING_SBI_HTTP2_PORT "HTTP2_PORT"
#define UDM_CONFIG_STRING_INTERFACE_NAME "INTERFACE_NAME"
#define UDM_CONFIG_STRING_IPV4_ADDRESS "IPV4_ADDRESS"
#define UDM_CONFIG_STRING_PORT "PORT"
#define UDM_CONFIG_STRING_PPID "PPID"
#define UDM_CONFIG_STRING_API_VERSION "API_VERSION"

#define UDM_CONFIG_STRING_UDR "UDR"
#define UDM_CONFIG_STRING_UDR_IPV4_ADDRESS "IPV4_ADDRESS"
#define UDM_CONFIG_STRING_UDR_PORT "PORT"

#define UDM_CONFIG_STRING_SUPPORT_FEATURES "SUPPORT_FEATURES"
#define UDM_CONFIG_STRING_SUPPORT_FEATURES_USE_FQDN_DNS "USE_FQDN_DNS"
#define UDM_CONFIG_STRING_SUPPORT_FEATURES_USE_HTTP2 "USE_HTTP2"
#define UDM_CONFIG_STRING_FQDN_DNS "FQDN"

using namespace libconfig;

namespace oai::udm::config {

typedef struct interface_cfg_s {
  std::string if_name;
  struct in_addr addr4;
  struct in_addr network4;
  struct in6_addr addr6;
  unsigned int mtu;
  unsigned int port;
  std::string api_version;
} interface_cfg_t;

class udm_config {
 public:
  udm_config();
  ~udm_config();
  int load(const std::string& config_file);
  int load_interface(const Setting& if_cfg, interface_cfg_t& cfg);
  void display();

  unsigned int instance;
  std::string pid_dir;
  std::string udm_name;

  interface_cfg_t sbi;
  unsigned int sbi_http2_port;

  struct {
    struct in_addr ipv4_addr;
    unsigned int port;
    std::string api_version;
    std::string fqdn;
  } udr_addr;

  bool use_fqdn_dns;
  bool use_http2;
};

}  // namespace oai::udm::config

#endif


text:
// Tests might fail if you have creative characters in your path.  Sue me.
#include "util/file_piece.hh"

#include "util/file.hh"
#include "util/scoped.hh"

#define BOOST_TEST_MODULE FilePieceTest
#include <boost/test/unit_test.hpp>
#include <fstream>
#include <iostream>

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

namespace util {
namespace {

std::string FileLocation() {
  if (boost::unit_test::framework::master_test_suite().argc < 2) {
    return "file_piece.cc";
  }
  std::string ret(boost::unit_test::framework::master_test_suite().argv[1]);
  return ret;
}

/* istream */
BOOST_AUTO_TEST_CASE(IStream) {
  std::fstream ref(FileLocation().c_str(), std::ios::in);
  std::fstream backing(FileLocation().c_str(), std::ios::in);
  FilePiece test(backing);
  std::string ref_line;
  while (getline(ref, ref_line)) {
    StringPiece test_line(test.ReadLine());
    BOOST_CHECK_EQUAL(ref_line, test_line);
  }
  BOOST_CHECK_THROW(test.get(), EndOfFileException);
  BOOST_CHECK_THROW(test.get(), EndOfFileException);
}

/* mmap implementation */
BOOST_AUTO_TEST_CASE(MMapReadLine) {
  std::fstream ref(FileLocation().c_str(), std::ios::in);
  FilePiece test(FileLocation().c_str(), NULL, 1);
  std::string ref_line;
  while (getline(ref, ref_line)) {
    StringPiece test_line(test.ReadLine());
    // I submitted a bug report to ICU: http://bugs.icu-project.org/trac/ticket/7924
    if (!test_line.empty() || !ref_line.empty()) {
      BOOST_CHECK_EQUAL(ref_line, test_line);
    }
  }
  BOOST_CHECK_THROW(test.get(), EndOfFileException);
}

#if !defined(_WIN32) && !defined(_WIN64) && !defined(__APPLE__)
/* Apple isn't happy with the popen, fileno, dup.  And I don't want to
 * reimplement popen.  This is an issue with the test.
 */
/* read() implementation */
BOOST_AUTO_TEST_CASE(StreamReadLine) {
  std::fstream ref(FileLocation().c_str(), std::ios::in);

  std::string popen_args = "cat \"";
  popen_args += FileLocation();
  popen_args += '"';

  FILE *catter = popen(popen_args.c_str(), "r");
  BOOST_REQUIRE(catter);

  FilePiece test(dup(fileno(catter)), "file_piece.cc", NULL, 1);
  std::string ref_line;
  while (getline(ref, ref_line)) {
    StringPiece test_line(test.ReadLine());
    // I submitted a bug report to ICU: http://bugs.icu-project.org/trac/ticket/7924
    if (!test_line.empty() || !ref_line.empty()) {
      BOOST_CHECK_EQUAL(ref_line, test_line);
    }
  }
  BOOST_CHECK_THROW(test.get(), EndOfFileException);
  BOOST_REQUIRE(!pclose(catter));
}
#endif

#ifdef HAVE_ZLIB

// gzip file
BOOST_AUTO_TEST_CASE(PlainZipReadLine) {
  std::string location(FileLocation());
  std::fstream ref(location.c_str(), std::ios::in);

  std::string command("gzip <\"");
  command += location + "\" >\"" + location + "\".gz";

  BOOST_REQUIRE_EQUAL(0, system(command.c_str()));
  FilePiece test((location + ".gz").c_str(), NULL, 1);
  unlink((location + ".gz").c_str());
  std::string ref_line;
  while (getline(ref, ref_line)) {
    StringPiece test_line(test.ReadLine());
    // I submitted a bug report to ICU: http://bugs.icu-project.org/trac/ticket/7924
    if (!test_line.empty() || !ref_line.empty()) {
      BOOST_CHECK_EQUAL(ref_line, test_line);
    }
  }
  BOOST_CHECK_THROW(test.get(), EndOfFileException);
}

// gzip stream.  Apple doesn't like popen, fileno, dup.  This is an issue with
// the test.
#ifndef __APPLE__
BOOST_AUTO_TEST_CASE(StreamZipReadLine) {
  std::fstream ref(FileLocation().c_str(), std::ios::in);

  std::string command("gzip <\"");
  command += FileLocation() + "\"";

  FILE * catter = popen(command.c_str(), "r");
  BOOST_REQUIRE(catter);

  FilePiece test(dup(fileno(catter)), "file_piece.cc.gz", NULL, 1);
  std::string ref_line;
  while (getline(ref, ref_line)) {
    StringPiece test_line(test.ReadLine());
    // I submitted a bug report to ICU: http://bugs.icu-project.org/trac/ticket/7924
    if (!test_line.empty() || !ref_line.empty()) {
      BOOST_CHECK_EQUAL(ref_line, test_line);
    }
  }
  BOOST_CHECK_THROW(test.get(), EndOfFileException);
  BOOST_REQUIRE(!pclose(catter));
}
#endif // __APPLE__

#endif // HAVE_ZLIB

} // namespace
} // namespace util

ext: cc

max_stars_repo_name: anshsarkar/TailBench

max_issues_repo_name: anshsarkar/TailBench

max_forks_repo_name: anshsarkar/TailBench


text:
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include <deque>
#include <iostream>
#include <random>
#include <vector>

#include "cutil.hpp"
#include "qsufsort.hpp"
#include "util.hpp"

#include <boost/algorithm/string/classification.hpp> // Include boost::for is_any_of
#include <boost/algorithm/string/split.hpp> // Include for boost::split
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

namespace po = boost::program_options;
namespace fs = boost::filesystem;

po::variables_map parse_cmdargs(int argc, char const* argv[])
{
    po::variables_map vm;
    po::options_description desc("Allowed options");
    // clang-format off
    desc.add_options()
        ("help,h", "produce help message")
        ("num,n",po::value<size_t>()->required(), "number of integers per file")
        ("input,i",po::value<std::string>()->required(), "input file")
        ("text,t", "text instead of uint32_t output")
        ("word,w", "word instead of bytes")
        ("output,o",po::value<std::string>()->required(), "output prefix");
    // clang-format on
    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        if (vm.count("help")) {
            std::cout << desc << "\n";
            exit(EXIT_SUCCESS);
        }
        po::notify(vm);
    } catch (const po::required_option& e) {
        std::cout << desc;
        std::cerr << "Missing required option: " << e.what() << std::endl;
        exit(EXIT_FAILURE);
    } catch (po::error& e) {
        std::cout << desc;
        std::cerr << "Error parsing cmdargs: " << e.what() << std::endl;
        exit(EXIT_FAILURE);
    }

    return vm;
}

std::vector<int> word_parse(std::string input_file, size_t n)
{
    std::vector<int> T;
    auto file_content_u8 = read_file_u8(input_file);
    for (size_t i = 0; i < file_content_u8.size(); i++)
        file_content_u8[i] = std::tolower(file_content_u8[i]);
    std::string_view content_str(
        (const char*)file_content_u8.data(), file_content_u8.size());
    std::vector<std::string> words;
    boost::split(words, content_str, boost::is_any_of(";, \n.?'()-\""),
        boost::token_compress_on);
    std::unordered_map<std::string, uint32_t> str2id;
    std::locale loc;
    for (size_t i = 0; i < words.size(); i++) {
        const std::string& cur_word = words[i];
        auto itr = str2id.find(cur_word);
        if (itr != str2id.end()) {
            T.push_back(itr->second);
        } else {
            T.push_back(str2id.size() + 1);
            str2id[cur_word] = str2id.size() + 1;
        }
        if (T.size() >= n)
            break;
    }
    T.push_back(0);
    return T;
}

std::vector<int> byte_parse(std::string input_file, size_t n)
{
    std::vector<int> T;
    auto file_content_u8 = read_file_u8(input_file);
    size_t size = file_content_u8.size() + 1;
    if (size > n + 1)
        size = n + 1;
    T.resize(n + 1);
    T[T.size() - 1] = 0;
    for (size_t i = 0; i < n; i++)
        T[i] = file_content_u8[i];
    return T;
}

uint32_t get_mtf_rank(std::deque<int>& alphabet, int sym)
{
    auto itr = std::find(std::begin(alphabet), std::end(alphabet), sym);
    uint32_t rank = (uint32_t)std::distance(std::begin(alphabet), itr);
    alphabet.erase(itr);
    alphabet.push_front(sym);
    return rank;
}

int main(int argc, char const* argv[])
{
    auto cmdargs = parse_cmdargs(argc, argv);
    auto input_file = cmdargs["input"].as<std::string>();
    auto output_prefix = cmdargs["output"].as<std::string>();
    auto write_text = cmdargs.count("text") != 0;
    auto words = cmdargs.count("word") != 0;
    auto n = cmdargs["num"].as<size_t>();
    auto file_name = output_prefix;

    std::vector<int> T;
    {
        timer t("(1) parsing input");
        if (words) {
            file_name += "-WORD";
            T = word_parse(input_file, n);
        } else {
            file_name += "-CHAR";
            T = byte_parse(input_file, n);
        }
    }

    std::vector<int> text = T;
    std::vector<int> SA(T.size());
    const auto [min, max] = std::minmax_element(T.begin(), T.end() - 1);
    {
        std::cout << "text size = " << T.size() << " min_sym = " << *min
                  << " max_sym = " << *max << std::endl;
        timer t("(2) compute SA");
        suffixsort(T.data(), SA.data(), T.size() - 1, *max + 1, *min);
    }

    std::vector<int> BWT(T.size());
    {
        timer t("(3) compute BWT");
        for (size_t i = 0; i < text.size(); i++) {
            BWT[i] = SA[i] != 0 ? text[SA[i] - 1] : text.back();
        }
    }
    SA.resize(0);
    size_t seq_len = text.size() - 1;
    if (seq_len > n)
        seq_len = n;

    std::vector<uint32_t> MTF(seq_len);
    {
        timer t("(4) compute MTF");
        std::deque<int> alphabet;
        for (size_t i = 0; i <= *max; i++)
            alphabet.push_back(i);
        for (size_t i = 0; i < seq_len; i++) {
            auto sym = BWT[i];
            MTF[i] = get_mtf_rank(alphabet, sym);
        }
    }

    {

        std::vector<uint32_t> text_u32(seq_len);
        for (size_t i = 0; i < seq_len; i++)
            text_u32[i] = text[i];
        timer t("(5) write WORD file");
        if (write_text)
            write_file_text(text_u32, file_name + ".txt");
        else
            write_file_u32(text_u32, file_name + ".u32");
    }
    {
        timer t("(6) write MTF file");
        if (write_text)
            write_file_text(MTF, file_name + "-BWTMTF.txt");
        else
            write_file_u32(MTF, file_name + "-BWTMTF.u32");
    }
}

max_stars_repo_name: mpetri/ans-large-alphabet

max_issues_repo_name: mpetri/ans-large-alphabet

max_forks_repo_name: mpetri/ans-large-alphabet