PageRenderTime 25ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/iterators.cc

https://github.com/praet/ledger
C++ | 258 lines | 184 code | 41 blank | 33 comment | 37 complexity | 7a9a6f1cace8b667451b1239b965e83c MD5 | raw file
  1. /*
  2. * Copyright (c) 2003-2010, John Wiegley. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * - Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * - Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * - Neither the name of New Artisans LLC nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include <system.hh>
  32. #include "iterators.h"
  33. #include "journal.h"
  34. #include "compare.h"
  35. namespace ledger {
  36. void xacts_iterator::reset(journal_t& journal)
  37. {
  38. xacts_i = journal.xacts.begin();
  39. xacts_end = journal.xacts.end();
  40. xacts_uninitialized = false;
  41. }
  42. xact_t * xacts_iterator::operator()()
  43. {
  44. if (xacts_i != xacts_end)
  45. return *xacts_i++;
  46. else
  47. return NULL;
  48. }
  49. void journal_posts_iterator::reset(journal_t& journal)
  50. {
  51. xacts.reset(journal);
  52. xact_t * xact = xacts();
  53. if (xact != NULL)
  54. posts.reset(*xact);
  55. }
  56. post_t * journal_posts_iterator::operator()()
  57. {
  58. post_t * post = posts();
  59. if (post == NULL) {
  60. xact_t * xact = xacts();
  61. if (xact != NULL) {
  62. posts.reset(*xact);
  63. post = posts();
  64. }
  65. }
  66. return post;
  67. }
  68. void posts_commodities_iterator::reset(journal_t& journal)
  69. {
  70. journal_posts.reset(journal);
  71. std::set<commodity_t *> commodities;
  72. for (post_t * post = journal_posts(); post; post = journal_posts()) {
  73. commodity_t& comm(post->amount.commodity());
  74. if (comm.flags() & COMMODITY_NOMARKET)
  75. continue;
  76. commodities.insert(&comm);
  77. }
  78. std::map<string, xact_t *> xacts_by_commodity;
  79. foreach (commodity_t * comm, commodities) {
  80. if (optional<commodity_t::varied_history_t&> history =
  81. comm->varied_history()) {
  82. account_t * account = journal.master->find_account(comm->symbol());
  83. foreach (commodity_t::history_by_commodity_map::value_type& pair,
  84. history->histories) {
  85. foreach (commodity_t::history_map::value_type& hpair,
  86. pair.second.prices) {
  87. xact_t * xact;
  88. string symbol = hpair.second.commodity().symbol();
  89. std::map<string, xact_t *>::iterator i =
  90. xacts_by_commodity.find(symbol);
  91. if (i != xacts_by_commodity.end()) {
  92. xact = (*i).second;
  93. } else {
  94. xact = &temps.create_xact();
  95. xact_temps.push_back(xact);
  96. xact->payee = symbol;
  97. xact->_date = hpair.first.date();
  98. xacts_by_commodity.insert
  99. (std::pair<string, xact_t *>(symbol, xact));
  100. }
  101. bool post_already_exists = false;
  102. foreach (post_t * post, xact->posts) {
  103. if (post->_date == hpair.first.date() &&
  104. post->amount == hpair.second) {
  105. post_already_exists = true;
  106. break;
  107. }
  108. }
  109. if (! post_already_exists) {
  110. post_t& temp = temps.create_post(*xact, account);
  111. temp._date = hpair.first.date();
  112. temp.amount = hpair.second;
  113. temp.xdata().datetime = hpair.first;
  114. }
  115. }
  116. }
  117. }
  118. }
  119. xacts.xacts_i = xact_temps.begin();
  120. xacts.xacts_end = xact_temps.end();
  121. xacts.xacts_uninitialized = false;
  122. xact_t * xact = xacts();
  123. if (xact != NULL)
  124. posts.reset(*xact);
  125. }
  126. post_t * posts_commodities_iterator::operator()()
  127. {
  128. post_t * post = posts();
  129. if (post == NULL) {
  130. xact_t * xact = xacts();
  131. if (xact != NULL) {
  132. posts.reset(*xact);
  133. post = posts();
  134. }
  135. }
  136. return post;
  137. }
  138. account_t * basic_accounts_iterator::operator()()
  139. {
  140. while (! accounts_i.empty() &&
  141. accounts_i.back() == accounts_end.back()) {
  142. accounts_i.pop_back();
  143. accounts_end.pop_back();
  144. }
  145. if (accounts_i.empty())
  146. return NULL;
  147. account_t * account = (*(accounts_i.back()++)).second;
  148. assert(account);
  149. // If this account has children, queue them up to be iterated next.
  150. if (! account->accounts.empty())
  151. push_back(*account);
  152. return account;
  153. }
  154. void sorted_accounts_iterator::push_back(account_t& account)
  155. {
  156. accounts_list.push_back(accounts_deque_t());
  157. if (flatten_all) {
  158. push_all(account, accounts_list.back());
  159. std::stable_sort(accounts_list.back().begin(),
  160. accounts_list.back().end(),
  161. compare_items<account_t>(sort_cmp));
  162. #if defined(DEBUG_ON)
  163. if (SHOW_DEBUG("accounts.sorted")) {
  164. foreach (account_t * account, accounts_list.back())
  165. DEBUG("accounts.sorted",
  166. "Account (flat): " << account->fullname());
  167. }
  168. #endif
  169. } else {
  170. sort_accounts(account, accounts_list.back());
  171. }
  172. sorted_accounts_i.push_back(accounts_list.back().begin());
  173. sorted_accounts_end.push_back(accounts_list.back().end());
  174. }
  175. void sorted_accounts_iterator::push_all(account_t& account,
  176. accounts_deque_t& deque)
  177. {
  178. foreach (accounts_map::value_type& pair, account.accounts) {
  179. deque.push_back(pair.second);
  180. push_all(*pair.second, deque);
  181. }
  182. }
  183. void sorted_accounts_iterator::sort_accounts(account_t& account,
  184. accounts_deque_t& deque)
  185. {
  186. foreach (accounts_map::value_type& pair, account.accounts)
  187. deque.push_back(pair.second);
  188. std::stable_sort(deque.begin(), deque.end(),
  189. compare_items<account_t>(sort_cmp));
  190. #if defined(DEBUG_ON)
  191. if (SHOW_DEBUG("accounts.sorted")) {
  192. foreach (account_t * account, deque)
  193. DEBUG("accounts.sorted", "Account: " << account->fullname());
  194. }
  195. #endif
  196. }
  197. account_t * sorted_accounts_iterator::operator()()
  198. {
  199. while (! sorted_accounts_i.empty() &&
  200. sorted_accounts_i.back() == sorted_accounts_end.back()) {
  201. sorted_accounts_i.pop_back();
  202. sorted_accounts_end.pop_back();
  203. assert(! accounts_list.empty());
  204. accounts_list.pop_back();
  205. }
  206. if (sorted_accounts_i.empty())
  207. return NULL;
  208. account_t * account = *sorted_accounts_i.back()++;
  209. assert(account);
  210. // If this account has children, queue them up to be iterated next.
  211. if (! flatten_all && ! account->accounts.empty())
  212. push_back(*account);
  213. // Make sure the sorting value gets recalculated for this account
  214. account->xdata().drop_flags(ACCOUNT_EXT_SORT_CALC);
  215. return account;
  216. }
  217. } // namespace ledger