diff --git a/src/engine/include/queryresultprinter.hpp b/src/engine/include/queryresultprinter.hpp index 5e9c0cb6..c203d2ce 100644 --- a/src/engine/include/queryresultprinter.hpp +++ b/src/engine/include/queryresultprinter.hpp @@ -13,13 +13,13 @@ #include "market.hpp" #include "ordersconstraints.hpp" #include "queryresulttypes.hpp" +#include "simpletable.hpp" #include "withdrawsconstraints.hpp" namespace cct { class DeliveredWithdrawInfo; class LoggingInfo; -class SimpleTable; class TradeOptions; class WithdrawOptions; @@ -103,7 +103,7 @@ class QueryResultPrinter { void printTrades(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount amount, bool isPercentageTrade, CurrencyCode toCurrency, const TradeOptions &tradeOptions, CoincenterCommandType commandType) const; - void printTable(const SimpleTable &simpleTable) const; + void printTable(const SimpleTable &table) const; void printJson(const json &jsonData) const; diff --git a/src/engine/src/balanceperexchangeportfolio.cpp b/src/engine/src/balanceperexchangeportfolio.cpp index aa15bcb2..19a71706 100644 --- a/src/engine/src/balanceperexchangeportfolio.cpp +++ b/src/engine/src/balanceperexchangeportfolio.cpp @@ -27,7 +27,7 @@ SimpleTable BalancePerExchangePortfolio::getTable(bool wide) const { BalancePortfolio total = computeTotal(); CurrencyCode balanceCurrencyCode = total.empty() ? CurrencyCode() : total.front().equi.currencyCode(); const bool countEqui = !balanceCurrencyCode.isNeutral(); - SimpleTable::Row header("Currency", "Total amount on selected"); + table::Row header("Currency", "Total amount on selected"); if (countEqui) { total.sortByDecreasingEquivalentAmount(); @@ -51,7 +51,7 @@ SimpleTable BalancePerExchangePortfolio::getTable(bool wide) const { const int nbExchanges = _balancePerExchange.size(); for (const auto &[amount, equi] : total) { // Amounts impossible to convert have a zero value - SimpleTable::Row row(amount.currencyStr(), amount.amountStr()); + table::Row row(amount.currencyStr(), amount.amountStr()); if (countEqui) { row.emplace_back(equi.amountStr()); } @@ -63,8 +63,8 @@ SimpleTable BalancePerExchangePortfolio::getTable(bool wide) const { balanceTable.push_back(std::move(row)); } if (countEqui) { - balanceTable.push_back(SimpleTable::Row::kDivider); - SimpleTable::Row row("Total", "", ComputeTotalSum(total).amountStr()); + balanceTable.emplace_back(); + table::Row row("Total", "", ComputeTotalSum(total).amountStr()); if (wide) { for (int exchangePos = 0; exchangePos < nbExchanges; ++exchangePos) { row.emplace_back(""); diff --git a/src/engine/src/queryresultprinter.cpp b/src/engine/src/queryresultprinter.cpp index d38c64c5..66c3ba33 100644 --- a/src/engine/src/queryresultprinter.cpp +++ b/src/engine/src/queryresultprinter.cpp @@ -708,11 +708,13 @@ void QueryResultPrinter::printHealthCheck(const ExchangeHealthCheckStatus &healt json jsonData = HealthCheckJson(healthCheckPerExchange); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Health Check status"); + SimpleTable table; + table.reserve(1U + healthCheckPerExchange.size()); + table.emplace_back("Exchange", "Health Check status"); for (const auto &[e, healthCheckValue] : healthCheckPerExchange) { - simpleTable.emplace_back(e->name(), healthCheckValue ? "OK" : "Not OK!"); + table.emplace_back(e->name(), healthCheckValue ? "OK" : "Not OK!"); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -747,8 +749,6 @@ void QueryResultPrinter::printCurrencies(const CurrenciesPerExchange ¤cies json jsonData = CurrenciesJson(currenciesPerExchange); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Currency", "Supported exchanges", "Exchange code(s)", "Alt code(s)", "Can deposit to", - "Can withdraw from", "Is fiat"); // Compute all currencies for all exchanges CurrencyCodeVector allCurrencyCodes; @@ -757,8 +757,12 @@ void QueryResultPrinter::printCurrencies(const CurrenciesPerExchange ¤cies } RemoveDuplicates(allCurrencyCodes); + SimpleTable table; - simpleTable.reserve(1U + allCurrencyCodes.size()); + table.reserve(1U + allCurrencyCodes.size()); + + table.emplace_back("Currency", "Supported exchanges", "Exchange code(s)", "Alt code(s)", "Can deposit to", + "Can withdraw from", "Is fiat"); for (CurrencyCode cur : allCurrencyCodes) { string supportedExchanges; @@ -796,12 +800,11 @@ void QueryResultPrinter::printCurrencies(const CurrenciesPerExchange ¤cies pPrevExchange = exchange; } - simpleTable.emplace_back(cur.str(), std::move(supportedExchanges), std::move(exchangeCodes), - std::move(altCodes), std::move(canDeposit), std::move(canWithdraw), - isFiat.value_or(false)); + table.emplace_back(cur.str(), std::move(supportedExchanges), std::move(exchangeCodes), std::move(altCodes), + std::move(canDeposit), std::move(canWithdraw), isFiat.value_or(false)); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -828,13 +831,14 @@ void QueryResultPrinter::printMarkets(CurrencyCode cur1, CurrencyCode cur2, marketsCol.push_back('-'); cur2.appendStrTo(marketsCol); } - SimpleTable simpleTable("Exchange", std::move(marketsCol)); + SimpleTable table; + table.emplace_back("Exchange", std::move(marketsCol)); for (const auto &[e, markets] : marketsPerExchange) { for (Market mk : markets) { - simpleTable.emplace_back(e->name(), mk.str()); + table.emplace_back(e->name(), mk.str()); } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -850,17 +854,18 @@ void QueryResultPrinter::printTickerInformation(const ExchangeTickerMaps &exchan json jsonData = TickerInformationJson(exchangeTickerMaps); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Market", "Bid price", "Bid volume", "Ask price", "Ask volume"); + SimpleTable table; + table.emplace_back("Exchange", "Market", "Bid price", "Bid volume", "Ask price", "Ask volume"); for (const auto &[e, marketOrderBookMap] : exchangeTickerMaps) { for (const auto &[mk, marketOrderBook] : marketOrderBookMap) { - simpleTable.emplace_back(e->name(), mk.str(), marketOrderBook.highestBidPrice().str(), - marketOrderBook.amountAtBidPrice().str(), marketOrderBook.lowestAskPrice().str(), - marketOrderBook.amountAtAskPrice().str()); + table.emplace_back(e->name(), mk.str(), marketOrderBook.highestBidPrice().str(), + marketOrderBook.amountAtBidPrice().str(), marketOrderBook.lowestAskPrice().str(), + marketOrderBook.amountAtAskPrice().str()); } // Sort rows in lexicographical order for consistent output - std::sort(simpleTable.begin(), simpleTable.end()); + std::ranges::sort(table); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -916,11 +921,13 @@ void QueryResultPrinter::printDepositInfo(CurrencyCode depositCurrencyCode, case ApiOutputType::kFormattedTable: { string walletStr(depositCurrencyCode.str()); walletStr.append(" address"); - SimpleTable simpleTable("Exchange", "Account", std::move(walletStr), "Destination Tag"); + SimpleTable table; + table.reserve(1U + walletPerExchange.size()); + table.emplace_back("Exchange", "Account", std::move(walletStr), "Destination Tag"); for (const auto &[exchangePtr, wallet] : walletPerExchange) { - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), wallet.address(), wallet.tag()); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), wallet.address(), wallet.tag()); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -944,14 +951,18 @@ void QueryResultPrinter::printTrades(const TradeResultPerExchange &tradeResultPe string tradedToStr("Traded to amount ("); tradedToStr.append(TradeModeToStr(tradeOptions.tradeMode())); tradedToStr.push_back(')'); - SimpleTable simpleTable("Exchange", "Account", "From", std::move(tradedFromStr), std::move(tradedToStr), - "Status"); + SimpleTable table; + + table.reserve(1U + tradeResultPerExchange.size()); + table.emplace_back("Exchange", "Account", "From", std::move(tradedFromStr), std::move(tradedToStr), "Status"); + for (const auto &[exchangePtr, tradeResult] : tradeResultPerExchange) { const TradedAmounts &tradedAmounts = tradeResult.tradedAmounts(); - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), tradeResult.from().str(), - tradedAmounts.from.str(), tradedAmounts.to.str(), tradeResult.stateStr()); + + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), tradeResult.from().str(), + tradedAmounts.from.str(), tradedAmounts.to.str(), tradeResult.stateStr()); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -968,16 +979,17 @@ void QueryResultPrinter::printClosedOrders(const ClosedOrdersPerExchange &closed json jsonData = OrdersJson(CoincenterCommandType::kOrdersClosed, closedOrdersPerExchange, ordersConstraints); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Account", "Exchange Id", "Placed time", "Matched time", "Side", "Price", - "Matched Amount"); + SimpleTable table; + table.emplace_back("Exchange", "Account", "Exchange Id", "Placed time", "Matched time", "Side", "Price", + "Matched Amount"); for (const auto &[exchangePtr, closedOrders] : closedOrdersPerExchange) { for (const ClosedOrder &closedOrder : closedOrders) { - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), closedOrder.id(), - closedOrder.placedTimeStr(), closedOrder.matchedTimeStr(), closedOrder.sideStr(), - closedOrder.price().str(), closedOrder.matchedVolume().str()); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), closedOrder.id(), closedOrder.placedTimeStr(), + closedOrder.matchedTimeStr(), closedOrder.sideStr(), closedOrder.price().str(), + closedOrder.matchedVolume().str()); } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -994,16 +1006,17 @@ void QueryResultPrinter::printOpenedOrders(const OpenedOrdersPerExchange &opened json jsonData = OrdersJson(CoincenterCommandType::kOrdersOpened, openedOrdersPerExchange, ordersConstraints); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Account", "Exchange Id", "Placed time", "Side", "Price", "Matched Amount", - "Remaining Amount"); + SimpleTable table; + table.emplace_back("Exchange", "Account", "Exchange Id", "Placed time", "Side", "Price", "Matched Amount", + "Remaining Amount"); for (const auto &[exchangePtr, openedOrders] : openedOrdersPerExchange) { for (const OpenedOrder &openedOrder : openedOrders) { - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), openedOrder.id(), - openedOrder.placedTimeStr(), openedOrder.sideStr(), openedOrder.price().str(), - openedOrder.matchedVolume().str(), openedOrder.remainingVolume().str()); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), openedOrder.id(), openedOrder.placedTimeStr(), + openedOrder.sideStr(), openedOrder.price().str(), openedOrder.matchedVolume().str(), + openedOrder.remainingVolume().str()); } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1020,11 +1033,13 @@ void QueryResultPrinter::printCancelledOrders(const NbCancelledOrdersPerExchange json jsonData = OrdersCancelledJson(nbCancelledOrdersPerExchange, ordersConstraints); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Account", "Number of cancelled orders"); + SimpleTable table; + table.reserve(1U + nbCancelledOrdersPerExchange.size()); + table.emplace_back("Exchange", "Account", "Number of cancelled orders"); for (const auto &[exchangePtr, nbCancelledOrders] : nbCancelledOrdersPerExchange) { - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), nbCancelledOrders); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), nbCancelledOrders); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1041,14 +1056,15 @@ void QueryResultPrinter::printRecentDeposits(const DepositsPerExchange &deposits json jsonData = RecentDepositsJson(depositsPerExchange, depositsConstraints); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Account", "Exchange Id", "Received time", "Amount", "Status"); + SimpleTable table; + table.emplace_back("Exchange", "Account", "Exchange Id", "Received time", "Amount", "Status"); for (const auto &[exchangePtr, deposits] : depositsPerExchange) { for (const Deposit &deposit : deposits) { - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), deposit.id(), deposit.timeStr(), - deposit.amount().str(), deposit.statusStr()); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), deposit.id(), deposit.timeStr(), + deposit.amount().str(), deposit.statusStr()); } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1065,14 +1081,15 @@ void QueryResultPrinter::printRecentWithdraws(const WithdrawsPerExchange &withdr json jsonData = RecentWithdrawsJson(withdrawsPerExchange, withdrawsConstraints); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Account", "Exchange Id", "Sent time", "Net Emitted Amount", "Fee", "Status"); + SimpleTable table; + table.emplace_back("Exchange", "Account", "Exchange Id", "Sent time", "Net Emitted Amount", "Fee", "Status"); for (const auto &[exchangePtr, withdraws] : withdrawsPerExchange) { for (const Withdraw &withdraw : withdraws) { - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), withdraw.id(), withdraw.timeStr(), - withdraw.amount().str(), withdraw.withdrawFee().str(), withdraw.statusStr()); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), withdraw.id(), withdraw.timeStr(), + withdraw.amount().str(), withdraw.withdrawFee().str(), withdraw.statusStr()); } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1093,13 +1110,15 @@ void QueryResultPrinter::printConversion(MonetaryAmount amount, CurrencyCode tar conversionStrHeader.append(" converted into "); targetCurrencyCode.appendStrTo(conversionStrHeader); - SimpleTable simpleTable("Exchange", std::move(conversionStrHeader)); + SimpleTable table; + table.reserve(1U + conversionPerExchange.size()); + table.emplace_back("Exchange", std::move(conversionStrHeader)); for (const auto &[e, convertedAmount] : conversionPerExchange) { if (convertedAmount != 0) { - simpleTable.emplace_back(e->name(), convertedAmount.str()); + table.emplace_back(e->name(), convertedAmount.str()); } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1118,20 +1137,23 @@ void QueryResultPrinter::printConversionPath(Market mk, case ApiOutputType::kFormattedTable: { string conversionPathStrHeader("Fastest conversion path for "); conversionPathStrHeader.append(mk.str()); - SimpleTable simpleTable("Exchange", std::move(conversionPathStrHeader)); + SimpleTable table; + table.reserve(1U + conversionPathsPerExchange.size()); + table.emplace_back("Exchange", std::move(conversionPathStrHeader)); for (const auto &[e, conversionPath] : conversionPathsPerExchange) { - if (!conversionPath.empty()) { - string conversionPathStr; - for (Market market : conversionPath) { - if (!conversionPathStr.empty()) { - conversionPathStr.push_back(','); - } - conversionPathStr.append(market.str()); + if (conversionPath.empty()) { + continue; + } + string conversionPathStr; + for (Market market : conversionPath) { + if (!conversionPathStr.empty()) { + conversionPathStr.push_back(','); } - simpleTable.emplace_back(e->name(), std::move(conversionPathStr)); + conversionPathStr.append(market.str()); } + table.emplace_back(e->name(), std::move(conversionPathStr)); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1148,7 +1170,7 @@ void QueryResultPrinter::printWithdrawFees(const MonetaryAmountByCurrencySetPerE json jsonData = WithdrawFeesJson(withdrawFeesPerExchange, cur); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable::Row header("Withdraw fee currency"); + table::Row header("Withdraw fee currency"); CurrencyCodeVector allCurrencyCodes; for (const auto &[e, withdrawFees] : withdrawFeesPerExchange) { header.emplace_back(e->name()); @@ -1159,9 +1181,12 @@ void QueryResultPrinter::printWithdrawFees(const MonetaryAmountByCurrencySetPerE RemoveDuplicates(allCurrencyCodes); - SimpleTable simpleTable(std::move(header)); + SimpleTable table; + table.reserve(1U + allCurrencyCodes.size()); + + table.emplace_back(std::move(header)); for (CurrencyCode cur : allCurrencyCodes) { - auto &row = simpleTable.emplace_back(cur.str()); + auto &row = table.emplace_back(cur.str()); for (const auto &[e, withdrawFees] : withdrawFeesPerExchange) { auto it = withdrawFees.find(cur); if (it == withdrawFees.end()) { @@ -1171,7 +1196,7 @@ void QueryResultPrinter::printWithdrawFees(const MonetaryAmountByCurrencySetPerE } } } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1191,11 +1216,13 @@ void QueryResultPrinter::printLast24hTradedVolume(Market mk, string headerTradedVolume("Last 24h "); headerTradedVolume.append(mk.str()); headerTradedVolume.append(" traded volume"); - SimpleTable simpleTable("Exchange", std::move(headerTradedVolume)); + SimpleTable table; + table.reserve(1U + tradedVolumePerExchange.size()); + table.emplace_back("Exchange", std::move(headerTradedVolume)); for (const auto &[e, tradedVolume] : tradedVolumePerExchange) { - simpleTable.emplace_back(e->name(), tradedVolume.str()); + table.emplace_back(e->name(), tradedVolume.str()); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1223,24 +1250,26 @@ void QueryResultPrinter::printLastTrades(Market mk, int nbLastTrades, string title(exchangePtr->name()); title.append(" trades"); - SimpleTable simpleTable(std::move(title), std::move(buyTitle), std::move(priceTitle), std::move(sellTitle)); + SimpleTable table; + table.reserve(1U + lastTrades.size() + (lastTrades.empty() ? 0U : 2U)); + table.emplace_back(std::move(title), std::move(buyTitle), std::move(priceTitle), std::move(sellTitle)); std::array totalAmounts{MonetaryAmount(0, mk.base()), MonetaryAmount(0, mk.base())}; MonetaryAmount totalPrice(0, mk.quote()); std::array nb{}; for (const PublicTrade &trade : lastTrades) { if (trade.side() == TradeSide::kBuy) { - simpleTable.emplace_back(trade.timeStr(), trade.amount().amountStr(), trade.price().amountStr(), ""); + table.emplace_back(trade.timeStr(), trade.amount().amountStr(), trade.price().amountStr(), ""); totalAmounts[0] += trade.amount(); ++nb[0]; } else { - simpleTable.emplace_back(trade.timeStr(), "", trade.price().amountStr(), trade.amount().amountStr()); + table.emplace_back(trade.timeStr(), "", trade.price().amountStr(), trade.amount().amountStr()); totalAmounts[1] += trade.amount(); ++nb[1]; } totalPrice += trade.price(); } if (nb[0] + nb[1] > 0) { - simpleTable.push_back(SimpleTable::Row::kDivider); + table.emplace_back(); std::array summary; for (int buyOrSell = 0; buyOrSell < 2; ++buyOrSell) { summary[buyOrSell].append(totalAmounts[buyOrSell].str()); @@ -1252,10 +1281,10 @@ void QueryResultPrinter::printLastTrades(Market mk, int nbLastTrades, } MonetaryAmount avgPrice = totalPrice / (nb[0] + nb[1]); - simpleTable.emplace_back("Summary", std::move(summary[0]), avgPrice.str(), std::move(summary[1])); + table.emplace_back("Summary", std::move(summary[0]), avgPrice.str(), std::move(summary[1])); } - printTable(simpleTable); + printTable(table); } break; } @@ -1274,11 +1303,13 @@ void QueryResultPrinter::printLastPrice(Market mk, const MonetaryAmountPerExchan case ApiOutputType::kFormattedTable: { string headerLastPrice(mk.str()); headerLastPrice.append(" last price"); - SimpleTable simpleTable("Exchange", std::move(headerLastPrice)); + SimpleTable table; + table.reserve(1U + pricePerExchange.size()); + table.emplace_back("Exchange", std::move(headerLastPrice)); for (const auto &[e, lastPrice] : pricePerExchange) { - simpleTable.emplace_back(e->name(), lastPrice.str()); + table.emplace_back(e->name(), lastPrice.str()); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1300,13 +1331,14 @@ void QueryResultPrinter::printWithdraw(const DeliveredWithdrawInfoWithExchanges WithdrawJson(deliveredWithdrawInfo, grossAmount, isPercentageWithdraw, fromExchange, toExchange, withdrawOptions); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("From Exchange", "From Account", "Gross withdraw amount", "Initiated time", "To Exchange", - "To Account", "Net received amount", "Received time"); - simpleTable.emplace_back(fromExchange.name(), fromExchange.keyName(), grossAmount.str(), - ToString(deliveredWithdrawInfo.initiatedTime()), toExchange.name(), toExchange.keyName(), - deliveredWithdrawInfo.receivedAmount().str(), - ToString(deliveredWithdrawInfo.receivedTime())); - printTable(simpleTable); + SimpleTable table; + table.reserve(2U); + table.emplace_back("From Exchange", "From Account", "Gross withdraw amount", "Initiated time", "To Exchange", + "To Account", "Net received amount", "Received time"); + table.emplace_back(fromExchange.name(), fromExchange.keyName(), grossAmount.str(), + ToString(deliveredWithdrawInfo.initiatedTime()), toExchange.name(), toExchange.keyName(), + deliveredWithdrawInfo.receivedAmount().str(), ToString(deliveredWithdrawInfo.receivedTime())); + printTable(table); break; } case ApiOutputType::kJson: @@ -1324,21 +1356,23 @@ void QueryResultPrinter::printDustSweeper( json jsonData = DustSweeperJson(tradedAmountsVectorWithFinalAmountPerExchange, currencyCode); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Account", "Trades", "Final Amount"); + SimpleTable table; + table.reserve(1U + tradedAmountsVectorWithFinalAmountPerExchange.size()); + + table.emplace_back("Exchange", "Account", "Trades", "Final Amount"); - simpleTable.reserve(1U + tradedAmountsVectorWithFinalAmountPerExchange.size()); for (const auto &[exchangePtr, tradedAmountsVectorWithFinalAmount] : tradedAmountsVectorWithFinalAmountPerExchange) { - SimpleTable::Cell tradesCell; + table::Cell tradesCell; const auto &tradedAmountsVector = tradedAmountsVectorWithFinalAmount.tradedAmountsVector; tradesCell.reserve(tradedAmountsVector.size()); for (const auto &tradedAmounts : tradedAmountsVector) { tradesCell.emplace_back(tradedAmounts.str()); } - simpleTable.emplace_back(exchangePtr->name(), exchangePtr->keyName(), std::move(tradesCell), - tradedAmountsVectorWithFinalAmount.finalAmount.str()); + table.emplace_back(exchangePtr->name(), exchangePtr->keyName(), std::move(tradesCell), + tradedAmountsVectorWithFinalAmount.finalAmount.str()); } - printTable(simpleTable); + printTable(table); break; } case ApiOutputType::kJson: @@ -1350,11 +1384,11 @@ void QueryResultPrinter::printDustSweeper( logActivity(CoincenterCommandType::kDustSweeper, jsonData); } -void QueryResultPrinter::printTable(const SimpleTable &simpleTable) const { +void QueryResultPrinter::printTable(const SimpleTable &table) const { std::ostringstream ss; std::ostream &os = _pOs != nullptr ? *_pOs : ss; - os << simpleTable; + os << table; if (_pOs != nullptr) { *_pOs << '\n'; diff --git a/src/objects/src/marketorderbook.cpp b/src/objects/src/marketorderbook.cpp index b7008c7f..df454256 100644 --- a/src/objects/src/marketorderbook.cpp +++ b/src/objects/src/marketorderbook.cpp @@ -675,7 +675,7 @@ SimpleTable MarketOrderBook::getTable(std::string_view exchangeName, const int pos = op - 1; MonetaryAmount amount(std::abs(_orders[pos].amount), CurrencyCode(), _volAndPriNbDecimals.volNbDecimals); MonetaryAmount price = priceAt(pos); - SimpleTable::Row row(amount.str()); + table::Row row(amount.str()); row.emplace_back(price.amountStr()); if (conversionPriceRate) { MonetaryAmount convertedPrice = price.toNeutral() * conversionPriceRate->toNeutral(); diff --git a/src/tech/include/simpletable.hpp b/src/tech/include/simpletable.hpp index c5764f24..11950bbd 100644 --- a/src/tech/include/simpletable.hpp +++ b/src/tech/include/simpletable.hpp @@ -28,8 +28,7 @@ namespace cct { /// No line separator will be placed between two single line only cells. /// However, multi line Rows ('Row' containing at least a 'Cell' with several 'CellLine's) will have line separators /// before and after them. -/// It is also possible to force a line separator between any row in the print. For that, you can insert the special Row -/// Row::kDivider at the desired place in the SimpleTable. +/// Empty rows are legal and will force the print of a divider line. /// See the unit test to have an overview of its usage and the look and feel of the print. /// Example: /// @@ -44,245 +43,177 @@ namespace cct { /// | 12 | | Nothing here | /// | -4 | | | /// +---------------+----------+-----------------------+ -class SimpleTable { - public: - class Row; - class Cell; - /// Cell in a SimpleTable on a single line. - /// Can currently hold only 4 types of values: a string, a string_view, a int64_t and a bool. - class CellLine { - public: +namespace table { + +/// Cell in a SimpleTable on a single line. +/// Can currently hold only 4 types of values: a string, a string_view, a int64_t and a bool. +class CellLine { + public: #ifdef CCT_MSVC - // folly::string does not support operator<< correctly with alignments with MSVC. Hence we use std::string - // in SimpleTable to guarantee correct alignment of formatted table. Referenced in this issue: - // https://github.com/facebook/folly/issues/1681 - using string_type = std::string; + // folly::string does not support operator<< correctly with alignments with MSVC. Hence we use std::string + // in SimpleTable to guarantee correct alignment of formatted table. Referenced in this issue: + // https://github.com/facebook/folly/issues/1681 + using string_type = std::string; #else - using string_type = string; + using string_type = string; #endif - using value_type = std::variant; - using size_type = uint32_t; - - CellLine() noexcept = default; + using value_type = std::variant; + using size_type = uint32_t; - explicit CellLine(std::string_view sv) : _data(sv) {} + explicit CellLine(std::string_view sv) : _data(sv) {} - explicit CellLine(const char *cstr) : _data(std::string_view(cstr)) {} + explicit CellLine(const char *cstr) : _data(std::string_view(cstr)) {} #ifdef CCT_MSVC - explicit CellLine(const string &v) : _data(string_type(v.data(), v.size())) {} + explicit CellLine(const string &v) : _data(string_type(v.data(), v.size())) {} #else - explicit CellLine(const string_type &str) : _data(str) {} + explicit CellLine(const string_type &str) : _data(str) {} - explicit CellLine(string_type &&str) : _data(std::move(str)) {} + explicit CellLine(string_type &&str) : _data(std::move(str)) {} #endif - explicit CellLine(std::integral auto val) : _data(val) {} - - // Number of chars of this single line cell value. - size_type width() const; - - void swap(CellLine &rhs) noexcept { _data.swap(rhs._data); } - - using trivially_relocatable = is_trivially_relocatable::type; - - std::strong_ordering operator<=>(const CellLine &) const noexcept = default; - - friend std::ostream &operator<<(std::ostream &os, const CellLine &singleLineCell); - - private: - value_type _data; - }; - - class Cell { - public: - using value_type = CellLine; - using size_type = uint32_t; - - private: - using CellLineVector = SmallVector; - - public: - using iterator = CellLineVector::iterator; - using const_iterator = CellLineVector::const_iterator; - - Cell() noexcept = default; - - /// Implicit constructor of a Cell from a CellLine. - Cell(CellLine singleLineCell) { _singleLineCells.push_back(std::move(singleLineCell)); } - - /// Creates a new Row with given list of cells. - template - explicit Cell(Args &&...singleLineCells) { - ([&](auto &&input) { _singleLineCells.emplace_back(std::forward(input)); }( - std::forward(singleLineCells)), - ...); - } - - iterator begin() noexcept { return _singleLineCells.begin(); } - const_iterator begin() const noexcept { return _singleLineCells.begin(); } - - iterator end() noexcept { return _singleLineCells.end(); } - const_iterator end() const noexcept { return _singleLineCells.end(); } - - value_type &front() { return _singleLineCells.front(); } - const value_type &front() const { return _singleLineCells.front(); } - - value_type &back() { return _singleLineCells.back(); } - const value_type &back() const { return _singleLineCells.back(); } - - void push_back(const value_type &cell) { _singleLineCells.push_back(cell); } - void push_back(value_type &&cell) { _singleLineCells.push_back(std::move(cell)); } - - template - value_type &emplace_back(Args &&...args) { - return _singleLineCells.emplace_back(std::forward(args)...); - } - - size_type size() const noexcept { return _singleLineCells.size(); } - - size_type width() const; - - value_type &operator[](size_type cellPos) { return _singleLineCells[cellPos]; } - const value_type &operator[](size_type cellPos) const { return _singleLineCells[cellPos]; } + explicit CellLine(std::integral auto val) : _data(val) {} - void reserve(size_type sz) { _singleLineCells.reserve(sz); } + // Number of chars of this single line cell value. + size_type width() const; - void swap(Cell &rhs) noexcept { _singleLineCells.swap(rhs._singleLineCells); } + void swap(CellLine &rhs) noexcept { _data.swap(rhs._data); } - using trivially_relocatable = is_trivially_relocatable::type; + using trivially_relocatable = is_trivially_relocatable::type; - std::strong_ordering operator<=>(const Cell &) const noexcept = default; + std::strong_ordering operator<=>(const CellLine &) const noexcept = default; - private: - friend class Row; + friend std::ostream &operator<<(std::ostream &os, const CellLine &singleLineCell); - void print(std::ostream &os, size_type linePos, size_type maxCellWidth) const; - - CellLineVector _singleLineCells; - }; - - /// Row in a SimpleTable. - class Row { - public: - using value_type = Cell; - using size_type = uint32_t; - - private: - using CellVector = vector; - - public: - using iterator = CellVector::iterator; - using const_iterator = CellVector::const_iterator; - - static const Row kDivider; + private: + value_type _data; +}; - Row() noexcept = default; +class Row; +class Cell { + public: + using value_type = CellLine; + using size_type = uint32_t; - /// Creates a new Row with given list of cells. - template - explicit Row(Args &&...cells) { - ([&](auto &&input) { _cells.emplace_back(std::forward(input)); }(std::forward(cells)), - ...); - } + private: + using CellLineVector = SmallVector; - iterator begin() noexcept { return _cells.begin(); } - const_iterator begin() const noexcept { return _cells.begin(); } + public: + using iterator = CellLineVector::iterator; + using const_iterator = CellLineVector::const_iterator; - iterator end() noexcept { return _cells.end(); } - const_iterator end() const noexcept { return _cells.end(); } + /// Implicit constructor of a Cell from a CellLine. + Cell(CellLine singleLineCell) { _singleLineCells.push_back(std::move(singleLineCell)); } - value_type &front() { return _cells.front(); } - const value_type &front() const { return _cells.front(); } + /// Creates a new Row with given list of cells. + template + explicit Cell(Args &&...singleLineCells) { + ([&](auto &&input) { _singleLineCells.emplace_back(std::forward(input)); }( + std::forward(singleLineCells)), + ...); + } - value_type &back() { return _cells.back(); } - const value_type &back() const { return _cells.back(); } + iterator begin() noexcept { return _singleLineCells.begin(); } + const_iterator begin() const noexcept { return _singleLineCells.begin(); } - void push_back(const value_type &cell) { _cells.push_back(cell); } - void push_back(value_type &&cell) { _cells.push_back(std::move(cell)); } + iterator end() noexcept { return _singleLineCells.end(); } + const_iterator end() const noexcept { return _singleLineCells.end(); } - template - value_type &emplace_back(Args &&...args) { - return _cells.emplace_back(std::forward(args)...); - } + value_type &front() { return _singleLineCells.front(); } + const value_type &front() const { return _singleLineCells.front(); } - size_type size() const noexcept { return _cells.size(); } + value_type &back() { return _singleLineCells.back(); } + const value_type &back() const { return _singleLineCells.back(); } - bool isMultiLine() const noexcept; + void push_back(const value_type &cell) { _singleLineCells.push_back(cell); } + void push_back(value_type &&cell) { _singleLineCells.push_back(std::move(cell)); } - bool isDivider() const noexcept { return _cells.empty(); } + template + value_type &emplace_back(Args &&...args) { + return _singleLineCells.emplace_back(std::forward(args)...); + } - void reserve(size_type sz) { _cells.reserve(sz); } + size_type size() const noexcept { return _singleLineCells.size(); } - value_type &operator[](size_type cellPos) { return _cells[cellPos]; } - const value_type &operator[](size_type cellPos) const { return _cells[cellPos]; } + size_type width() const; - void swap(Row &rhs) noexcept { _cells.swap(rhs._cells); } + value_type &operator[](size_type cellPos) { return _singleLineCells[cellPos]; } + const value_type &operator[](size_type cellPos) const { return _singleLineCells[cellPos]; } - using trivially_relocatable = is_trivially_relocatable::type; + void reserve(size_type sz) { _singleLineCells.reserve(sz); } - std::strong_ordering operator<=>(const Row &) const noexcept = default; + void swap(Cell &rhs) noexcept { _singleLineCells.swap(rhs._singleLineCells); } - private: - friend std::ostream &operator<<(std::ostream &, const SimpleTable &); + using trivially_relocatable = is_trivially_relocatable::type; - void print(std::ostream &os, std::span maxWidthPerColumn) const; + std::strong_ordering operator<=>(const Cell &) const noexcept = default; - CellVector _cells; - }; + private: + CellLineVector _singleLineCells; +}; - using value_type = Row; +/// Row in a SimpleTable. +class Row { + public: + using value_type = Cell; using size_type = uint32_t; private: - using RowVector = vector; + using CellVector = vector; public: - using iterator = RowVector::iterator; - using const_iterator = RowVector::const_iterator; - - SimpleTable() noexcept = default; + using iterator = CellVector::iterator; + using const_iterator = CellVector::const_iterator; + /// Creates a new Row with given list of cells. template - explicit SimpleTable(Args &&...args) { - _rows.emplace_back(std::forward(args)...); + explicit Row(Args &&...cells) { + ([&](auto &&input) { _cells.emplace_back(std::forward(input)); }(std::forward(cells)), ...); } - iterator begin() noexcept { return _rows.begin(); } - iterator end() noexcept { return _rows.end(); } + iterator begin() noexcept { return _cells.begin(); } + const_iterator begin() const noexcept { return _cells.begin(); } - const_iterator begin() const noexcept { return _rows.begin(); } - const_iterator end() const noexcept { return _rows.end(); } + iterator end() noexcept { return _cells.end(); } + const_iterator end() const noexcept { return _cells.end(); } - const value_type &front() const { return _rows.front(); } - const value_type &back() const { return _rows.back(); } + value_type &front() { return _cells.front(); } + const value_type &front() const { return _cells.front(); } - void push_back(const Row &row) { _rows.push_back(row); } - void push_back(Row &&row) { _rows.push_back(std::move(row)); } + value_type &back() { return _cells.back(); } + const value_type &back() const { return _cells.back(); } + + void push_back(const value_type &cell) { _cells.push_back(cell); } + void push_back(value_type &&cell) { _cells.push_back(std::move(cell)); } template value_type &emplace_back(Args &&...args) { - return _rows.emplace_back(std::forward(args)...); + return _cells.emplace_back(std::forward(args)...); } - size_type size() const noexcept { return _rows.size(); } - bool empty() const noexcept { return _rows.empty(); } + size_type size() const noexcept { return _cells.size(); } - value_type &operator[](size_type rowPos) { return _rows[rowPos]; } - const value_type &operator[](size_type rowPos) const { return _rows[rowPos]; } + bool empty() const noexcept { return _cells.empty(); } - void reserve(size_type sz) { _rows.reserve(sz); } + void reserve(size_type sz) { _cells.reserve(sz); } - friend std::ostream &operator<<(std::ostream &os, const SimpleTable &table); + value_type &operator[](size_type cellPos) { return _cells[cellPos]; } + const value_type &operator[](size_type cellPos) const { return _cells[cellPos]; } - using trivially_relocatable = is_trivially_relocatable::type; + void swap(Row &rhs) noexcept { _cells.swap(rhs._cells); } - private: - using MaxWidthPerColumnVector = SmallVector; + using trivially_relocatable = is_trivially_relocatable::type; - MaxWidthPerColumnVector computeMaxWidthPerColumn() const; + std::strong_ordering operator<=>(const Row &) const noexcept = default; - RowVector _rows; + private: + CellVector _cells; }; + +} // namespace table + +using SimpleTable = vector; + +std::ostream &operator<<(std::ostream &os, const SimpleTable &table); } // namespace cct \ No newline at end of file diff --git a/src/tech/src/simpletable.cpp b/src/tech/src/simpletable.cpp index ba5cd800..f5c7c086 100644 --- a/src/tech/src/simpletable.cpp +++ b/src/tech/src/simpletable.cpp @@ -11,13 +11,12 @@ #include #include +#include "cct_smallvector.hpp" #include "mathhelpers.hpp" namespace cct { -/// A divider row is represented as an empty row. -/// It will be treated specially in the print -const SimpleTable::Row SimpleTable::Row::kDivider; +namespace table { namespace { constexpr char kColumnSep = '|'; @@ -46,7 +45,7 @@ template constexpr bool always_false_v = false; } // namespace -SimpleTable::size_type SimpleTable::CellLine::width() const { +CellLine::size_type CellLine::width() const { return std::visit( [](auto &&val) -> size_type { using T = std::decay_t; @@ -65,15 +64,15 @@ SimpleTable::size_type SimpleTable::CellLine::width() const { _data); } -std::ostream &operator<<(std::ostream &os, const SimpleTable::CellLine &singleLineCell) { +std::ostream &operator<<(std::ostream &os, const CellLine &singleLineCell) { std::visit( [&os](auto &&val) { using T = std::decay_t; if constexpr (std::is_same_v) { os << (val ? kBoolValueTrue : kBoolValueFalse); - } else if constexpr (std::is_same_v || - std::is_same_v || std::is_integral_v) { + } else if constexpr (std::is_same_v || std::is_same_v || + std::is_integral_v) { os << val; } else { // Note: can be replaced with 'static_assert(false);' in C++23 @@ -84,17 +83,22 @@ std::ostream &operator<<(std::ostream &os, const SimpleTable::CellLine &singleLi return os; } -SimpleTable::Cell::size_type SimpleTable::Cell::width() const { +Cell::size_type Cell::width() const { const auto maxWidthLineIt = std::ranges::max_element( _singleLineCells, [](const auto &lhs, const auto &rhs) { return lhs.width() < rhs.width(); }); return maxWidthLineIt == _singleLineCells.end() ? size_type{} : maxWidthLineIt->width(); } -void SimpleTable::Cell::print(std::ostream &os, size_type linePos, size_type maxCellWidth) const { +namespace { +bool IsMultiLine(const Row &row) { + return std::ranges::any_of(row, [](const auto &cell) { return cell.size() > 1U; }); +} + +void PrintCell(std::ostream &os, const Cell &cell, Cell::size_type linePos, Cell::size_type maxCellWidth) { os << ' ' << Align(AlignTo::kLeft) << std::setw(maxCellWidth); - if (linePos < size()) { - os << _singleLineCells[linePos]; + if (linePos < cell.size()) { + os << cell[linePos]; } else { // No value for this line pos for given cell, just print spaces os << kEmptyValueChar; @@ -103,56 +107,55 @@ void SimpleTable::Cell::print(std::ostream &os, size_type linePos, size_type max os << ' ' << kColumnSep; } -bool SimpleTable::Row::isMultiLine() const noexcept { - return std::ranges::any_of(_cells, [](const Cell &cell) { return cell.size() > 1U; }); -} - -void SimpleTable::Row::print(std::ostream &os, std::span maxWidthPerColumn) const { +void PrintRow(std::ostream &os, const Row &row, std::span maxWidthPerColumn) { const auto maxSingleLineCellsIt = - std::ranges::max_element(_cells, [](const Cell &lhs, const Cell &rhs) { return lhs.size() < rhs.size(); }); - const auto maxNbSingleLineCells = maxSingleLineCellsIt == _cells.end() ? size_type{} : maxSingleLineCellsIt->size(); - for (std::remove_const_t linePos = 0; linePos < maxNbSingleLineCells; ++linePos) { + std::ranges::max_element(row, [](const auto &lhs, const auto &rhs) { return lhs.size() < rhs.size(); }); + const auto maxNbSingleLineCells = maxSingleLineCellsIt == row.end() ? 0 : maxSingleLineCellsIt->size(); + using size_type = std::remove_const_t; + for (size_type linePos = 0; linePos < maxNbSingleLineCells; ++linePos) { os << kColumnSep; size_type columnPos{}; - for (const Cell &cell : _cells) { - cell.print(os, linePos, maxWidthPerColumn[columnPos]); + for (const auto &cell : row) { + PrintCell(os, cell, linePos, maxWidthPerColumn[columnPos]); ++columnPos; } os << '\n'; } } +} // namespace + +} // namespace table -SimpleTable::MaxWidthPerColumnVector SimpleTable::computeMaxWidthPerColumn() const { - // We assume that each row has same number of cells - const size_type nbColumns = _rows.front().size(); - MaxWidthPerColumnVector res(nbColumns, 0); - for (const Row &row : _rows) { - if (row.isDivider()) { +namespace { +auto ComputeMaxWidthPerColumn(const SimpleTable &table) { + const auto nbColumns = table.front().size(); + SmallVector res(nbColumns, 0); + for (const auto &row : table) { + if (row.empty()) { continue; } - for (size_type columnPos = 0; columnPos < nbColumns; ++columnPos) { - const Cell &cell = row[columnPos]; - res[columnPos] = std::max(res[columnPos], static_cast(cell.width())); + for (std::remove_const_t columnPos{}; columnPos < nbColumns; ++columnPos) { + res[columnPos] = std::max(res[columnPos], static_cast(row[columnPos].width())); } } return res; } -namespace { auto ComputeLineSep(std::span maxWidthPerColumnVector, char cellFiller, char columnSep) { - const SimpleTable::size_type sumWidths = - std::accumulate(maxWidthPerColumnVector.begin(), maxWidthPerColumnVector.end(), 0U); + using size_type = SimpleTable::size_type; + + const auto sumWidths = std::accumulate(maxWidthPerColumnVector.begin(), maxWidthPerColumnVector.end(), size_type{}); // 3 as one space before, one space after the field name and column separator. +1 for the first column separator - const SimpleTable::size_type tableWidth = sumWidths + maxWidthPerColumnVector.size() * 3 + 1; + const size_type tableWidth = sumWidths + maxWidthPerColumnVector.size() * 3 + 1; SimpleTable::value_type::value_type::value_type::string_type lineSep(tableWidth, cellFiller); - SimpleTable::size_type curWidth{}; + size_type curWidth{}; lineSep[curWidth] = columnSep; for (auto maxWidth : maxWidthPerColumnVector) { curWidth += maxWidth + 3; @@ -164,11 +167,11 @@ auto ComputeLineSep(std::span maxWidthPerColumnVector, char cell } // namespace std::ostream &operator<<(std::ostream &os, const SimpleTable &table) { - if (table._rows.empty()) { + if (table.empty()) { return os; } - const auto maxWidthPerColumnVector = table.computeMaxWidthPerColumn(); + const auto maxWidthPerColumnVector = ComputeMaxWidthPerColumn(table); const auto lineSep = ComputeLineSep(maxWidthPerColumnVector, '-', '+'); const auto multiLineSep = ComputeLineSep(maxWidthPerColumnVector, '~', '|'); @@ -176,28 +179,28 @@ std::ostream &operator<<(std::ostream &os, const SimpleTable &table) { bool isLastLineSep = false; for (SimpleTable::size_type rowPos{}, nbRows = table.size(); rowPos < nbRows; ++rowPos) { - const SimpleTable::Row &row = table[rowPos]; + const auto &row = table[rowPos]; - if (row.isDivider()) { + if (row.empty()) { os << lineSep << '\n'; isLastLineSep = true; continue; } - const bool isMultiLine = row.isMultiLine(); + const bool isMultiLine = table::IsMultiLine(row); if (isMultiLine && !isLastLineSep) { os << multiLineSep << '\n'; } - row.print(os, maxWidthPerColumnVector); + table::PrintRow(os, row, maxWidthPerColumnVector); if (rowPos == 0 && nbRows > 1) { // header sep os << lineSep << '\n'; isLastLineSep = true; } else { - isLastLineSep = isMultiLine && rowPos + 1 < nbRows && !table[rowPos + 1].isDivider(); + isLastLineSep = isMultiLine && rowPos + 1 < nbRows && !table[rowPos + 1].empty(); if (isLastLineSep) { os << multiLineSep << '\n'; diff --git a/src/tech/test/simpletable_test.cpp b/src/tech/test/simpletable_test.cpp index 106e725f..9000329e 100644 --- a/src/tech/test/simpletable_test.cpp +++ b/src/tech/test/simpletable_test.cpp @@ -37,17 +37,17 @@ TEST(SimpleTable, OneLinePrint) { TEST(SimpleTable, SimplePrint) { SimpleTable table; - SimpleTable::Row row1; + table::Row row1; row1.emplace_back("Amount"); row1.emplace_back("Currency"); row1.emplace_back("Is Fiat"); table.push_back(std::move(row1)); - SimpleTable::Row row2; + table::Row row2; row2.emplace_back("123.45"); row2.emplace_back("EUR"); row2.emplace_back(true); table.push_back(std::move(row2)); - SimpleTable::Row row3; + table::Row row3; row3.emplace_back(65); row3.emplace_back("BTC"); row3.emplace_back(false); @@ -77,7 +77,7 @@ class SimpleTableTest : public ::testing::Test { table.emplace_back(-677256340000, "KEBAB", "-34.09"); } - SimpleTable table{"Amount", "Currency", "This header is longer"}; + SimpleTable table{table::Row("Amount", "Currency", "This header is longer")}; }; TEST_F(SimpleTableTest, SettingRowDirectly) { @@ -108,8 +108,8 @@ TEST_F(SimpleTableTest, SettingRowDirectly) { TEST_F(SimpleTableTest, MultiLineFields) { fill(); - table[1][2].push_back(SimpleTable::CellLine("... but another line!")); - table[3][0].push_back(SimpleTable::CellLine(true)); + table[1][2].push_back(table::CellLine("... but another line!")); + table[3][0].push_back(table::CellLine(true)); table.emplace_back("999.25", "KRW", 16820100000000000000UL); @@ -139,7 +139,7 @@ TEST_F(SimpleTableTest, MultiLineFields) { TEST_F(SimpleTableTest, EmptyCellShouldBePossible) { fill(); - table.emplace_back(SimpleTable::Cell{12, -4}, SimpleTable::Cell{}, "Nothing here"); + table.emplace_back(table::Cell{12, -4}, table::Cell{}, "Nothing here"); std::ostringstream ss; @@ -169,9 +169,9 @@ class DividerLineTest : public ::testing::Test { table.emplace_back(1); table.emplace_back(2); table.emplace_back(""); - table.emplace_back(SimpleTable::Row::kDivider); + table.emplace_back(); table.emplace_back(4); - table.emplace_back(SimpleTable::Row::kDivider); + table.emplace_back(); } SimpleTable table; @@ -196,10 +196,10 @@ TEST_F(DividerLineTest, SingleLineRows) { } TEST_F(DividerLineTest, WithMultiLine) { - table[1][0].push_back(SimpleTable::CellLine(42)); - table[1][0].push_back(SimpleTable::CellLine(true)); + table[1][0].push_back(table::CellLine(42)); + table[1][0].push_back(table::CellLine(true)); - table[4][0].push_back(SimpleTable::CellLine(false)); + table[4][0].push_back(table::CellLine(false)); ss << '\n' << table;