<commit_before>#include "vision_cpu.h"

template <typename scalar_t>
at::Tensor nms_cpu_kernel(
    const at::Tensor& dets,
    const at::Tensor& scores,
    const float iou_threshold) {
  AT_ASSERTM(!dets.options().device().is_cuda(), "dets must be a CPU tensor");
  AT_ASSERTM(!scores.options().device().is_cuda(), "scores must be a CPU tensor");
  AT_ASSERTM(
      dets.scalar_type() == scores.scalar_type(), "dets should have the same type as scores");

  if (dets.numel() == 0)
    return at::empty({0}, dets.options().dtype(at::kLong));

  auto x1_t = dets.select(1, 0).contiguous();
  auto y1_t = dets.select(1, 1).contiguous();
  auto x2_t = dets.select(1, 2).contiguous();
  auto y2_t = dets.select(1, 3).contiguous();

  at::Tensor areas_t = (x2_t - x1_t) * (y2_t - y1_t);

  auto order_t = std::get<1>(scores.sort(0, /* descending=*/true));

  auto ndets = dets.size(0);
  at::Tensor suppressed_t = at::zeros({ndets}, dets.options().dtype(at::kByte));
  at::Tensor keep_t = at::zeros({ndets}, dets.options().dtype(at::kLong));

  auto suppressed = suppressed_t.data_ptr<uint8_t>();
  auto keep = keep_t.data_ptr<int64_t>();
  auto order = order_t.data_ptr<int64_t>();
  auto x1 = x1_t.data_ptr<scalar_t>();
  auto y1 = y1_t.data_ptr<scalar_t>();
  auto x2 = x2_t.data_ptr<scalar_t>();
  auto y2 = y2_t.data_ptr<scalar_t>();
  auto areas = areas_t.data_ptr<scalar_t>();

  int64_t num_to_keep = 0;

  for (int64_t _i = 0; _i < ndets; _i++) {
    auto i = order[_i];
    if (suppressed[i] == 1)
      continue;
    keep[num_to_keep++] = i;
    auto ix1 = x1[i];
    auto iy1 = y1[i];
    auto ix2 = x2[i];
    auto iy2 = y2[i];
    auto iarea = areas[i];

    for (int64_t _j = _i + 1; _j < ndets; _j++) {
      auto j = order[_j];
      if (suppressed[j] == 1)
        continue;
      auto xx1 = std::max(ix1, x1[j]);
      auto yy1 = std::max(iy1, y1[j]);
      auto xx2 = std::min(ix2, x2[j]);
      auto yy2 = std::min(iy2, y2[j]);

      auto w = std::max(static_cast<scalar_t>(0), xx2 - xx1);
      auto h = std::max(static_cast<scalar_t>(0), yy2 - yy1);
      auto inter = w * h;
      auto ovr = inter / (iarea + areas[j] - inter);
      if (ovr > iou_threshold)
        suppressed[j] = 1;
    }
  }
  return keep_t.narrow(/*dim=*/0, /*start=*/0, /*length=*/num_to_keep);
}

at::Tensor nms_cpu(
    const at::Tensor& dets,
    const at::Tensor& scores,
    const float iou_threshold) {
  auto result = at::empty({0}, dets.options());

  AT_DISPATCH_FLOATING_TYPES(dets.scalar_type(), "nms", [&] {
    result = nms_cpu_kernel<scalar_t>(dets, scores, iou_threshold);
  });
  return result;
}
<commit_msg>Fix C++ lint (#2059)<commit_after>#include "vision_cpu.h"

template <typename scalar_t>
at::Tensor nms_cpu_kernel(
    const at::Tensor& dets,
    const at::Tensor& scores,
    const float iou_threshold) {
  AT_ASSERTM(!dets.options().device().is_cuda(), "dets must be a CPU tensor");
  AT_ASSERTM(
      !scores.options().device().is_cuda(), "scores must be a CPU tensor");
  AT_ASSERTM(
      dets.scalar_type() == scores.scalar_type(),
      "dets should have the same type as scores");

  if (dets.numel() == 0)
    return at::empty({0}, dets.options().dtype(at::kLong));

  auto x1_t = dets.select(1, 0).contiguous();
  auto y1_t = dets.select(1, 1).contiguous();
  auto x2_t = dets.select(1, 2).contiguous();
  auto y2_t = dets.select(1, 3).contiguous();

  at::Tensor areas_t = (x2_t - x1_t) * (y2_t - y1_t);

  auto order_t = std::get<1>(scores.sort(0, /* descending=*/true));

  auto ndets = dets.size(0);
  at::Tensor suppressed_t = at::zeros({ndets}, dets.options().dtype(at::kByte));
  at::Tensor keep_t = at::zeros({ndets}, dets.options().dtype(at::kLong));

  auto suppressed = suppressed_t.data_ptr<uint8_t>();
  auto keep = keep_t.data_ptr<int64_t>();
  auto order = order_t.data_ptr<int64_t>();
  auto x1 = x1_t.data_ptr<scalar_t>();
  auto y1 = y1_t.data_ptr<scalar_t>();
  auto x2 = x2_t.data_ptr<scalar_t>();
  auto y2 = y2_t.data_ptr<scalar_t>();
  auto areas = areas_t.data_ptr<scalar_t>();

  int64_t num_to_keep = 0;

  for (int64_t _i = 0; _i < ndets; _i++) {
    auto i = order[_i];
    if (suppressed[i] == 1)
      continue;
    keep[num_to_keep++] = i;
    auto ix1 = x1[i];
    auto iy1 = y1[i];
    auto ix2 = x2[i];
    auto iy2 = y2[i];
    auto iarea = areas[i];

    for (int64_t _j = _i + 1; _j < ndets; _j++) {
      auto j = order[_j];
      if (suppressed[j] == 1)
        continue;
      auto xx1 = std::max(ix1, x1[j]);
      auto yy1 = std::max(iy1, y1[j]);
      auto xx2 = std::min(ix2, x2[j]);
      auto yy2 = std::min(iy2, y2[j]);

      auto w = std::max(static_cast<scalar_t>(0), xx2 - xx1);
      auto h = std::max(static_cast<scalar_t>(0), yy2 - yy1);
      auto inter = w * h;
      auto ovr = inter / (iarea + areas[j] - inter);
      if (ovr > iou_threshold)
        suppressed[j] = 1;
    }
  }
  return keep_t.narrow(/*dim=*/0, /*start=*/0, /*length=*/num_to_keep);
}

at::Tensor nms_cpu(
    const at::Tensor& dets,
    const at::Tensor& scores,
    const float iou_threshold) {
  auto result = at::empty({0}, dets.options());

  AT_DISPATCH_FLOATING_TYPES(dets.scalar_type(), "nms", [&] {
    result = nms_cpu_kernel<scalar_t>(dets, scores, iou_threshold);
  });
  return result;
}
<|endoftext|>


<commit_before>/*!
 * \copy
 *     Copyright (c)  2009-2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in
 *          the documentation and/or other materials provided with the
 *          distribution.
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *     POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * \file	utils.c
 *
 * \brief	common tool/function utilization
 *
 * \date	03/10/2009 Created
 *
 *************************************************************************************
 */
#include "utils.h"
#include "crt_util_safe_x.h"	// Safe CRT routines like utils for cross platforms
#include "codec_app_def.h"
float WelsCalcPsnr (const void* kpTarPic,
                    const int32_t kiTarStride,
                    const void* kpRefPic,
                    const int32_t kiRefStride,
                    const int32_t kiWidth,
                    const int32_t kiHeight);

void WelsLog (SLogContext* logCtx, int32_t iLevel, const char* kpFmt, ...) {
  va_list vl;
  char pTraceTag[MAX_LOG_SIZE];
  switch (iLevel) {
  case WELS_LOG_ERROR:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Error:");
    break;
  case WELS_LOG_WARNING:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Warning:");
    break;
  case WELS_LOG_INFO:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Info:");
    break;
  case WELS_LOG_DEBUG:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Debug:");
    break;
  default:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Detail:");
    break;
  }
  va_start (vl, pTraceTag);
  logCtx->pfLog (logCtx->pLogCtx, iLevel, pTraceTag, vl);
  va_end (vl);

  va_start (vl, kpFmt);
  logCtx->pfLog (logCtx->pLogCtx, iLevel, kpFmt, vl);
  va_end (vl);
}

#ifndef CALC_PSNR
#define CONST_FACTOR_PSNR	(10.0 / log(10.0))	// for good computation
#define CALC_PSNR(w, h, s)	((float)(CONST_FACTOR_PSNR * log( 65025.0 * w * h / iSqe )))
#endif//CALC_PSNR

/*
 *	PSNR calculation routines
 */
/*!
 *************************************************************************************
 * \brief	PSNR calculation utilization in Wels
 *
 * \param	pTarPic		target picture to be calculated in Picture pData format
 * \param	iTarStride	stride of target picture pData pBuffer
 * \param 	pRefPic		base referencing picture samples
 * \param	iRefStride	stride of reference picture pData pBuffer
 * \param	iWidth		picture iWidth in pixel
 * \param	iHeight		picture iHeight in pixel
 *
 * \return	actual PSNR result;
 *
 * \note	N/A
 *************************************************************************************
 */
float WelsCalcPsnr (const void* kpTarPic,
                    const int32_t kiTarStride,
                    const void* kpRefPic,
                    const int32_t kiRefStride,
                    const int32_t kiWidth,
                    const int32_t kiHeight) {
  int64_t	iSqe = 0;
  int32_t x, y;
  uint8_t* pTar = (uint8_t*)kpTarPic;
  uint8_t* pRef = (uint8_t*)kpRefPic;

  if (NULL == pTar || NULL == pRef)
    return (-1.0f);

  for (y = 0; y < kiHeight; ++ y) {	// OPTable !!
    for (x = 0; x < kiWidth; ++ x) {
      const int32_t kiT = pTar[y * kiTarStride + x] - pRef[y * kiRefStride + x];
      iSqe	+= kiT * kiT;
    }
  }
  if (0 == iSqe) {
    return (99.99f);
  }
  return CALC_PSNR (kiWidth, kiHeight, iSqe);
}

<commit_msg>modify trace output<commit_after>/*!
 * \copy
 *     Copyright (c)  2009-2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in
 *          the documentation and/or other materials provided with the
 *          distribution.
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *     POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * \file	utils.c
 *
 * \brief	common tool/function utilization
 *
 * \date	03/10/2009 Created
 *
 *************************************************************************************
 */
#include "utils.h"
#include "crt_util_safe_x.h"	// Safe CRT routines like utils for cross platforms
#include "codec_app_def.h"
float WelsCalcPsnr (const void* kpTarPic,
                    const int32_t kiTarStride,
                    const void* kpRefPic,
                    const int32_t kiRefStride,
                    const int32_t kiWidth,
                    const int32_t kiHeight);

void WelsLog (SLogContext* logCtx, int32_t iLevel, const char* kpFmt, ...) {
  va_list vl;
  char pTraceTag[MAX_LOG_SIZE];
  switch (iLevel) {
  case WELS_LOG_ERROR:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Error:");
    break;
  case WELS_LOG_WARNING:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Warning:");
    break;
  case WELS_LOG_INFO:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Info:");
    break;
  case WELS_LOG_DEBUG:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Debug:");
    break;
  default:
    WelsSnprintf (pTraceTag, MAX_LOG_SIZE, "[OpenH264] Detail:");
    break;
  }
  WelsStrcat(pTraceTag,MAX_LOG_SIZE,kpFmt);
  va_start (vl, kpFmt);
  logCtx->pfLog (logCtx->pLogCtx, iLevel, pTraceTag, vl);
  va_end (vl);
}

#ifndef CALC_PSNR
#define CONST_FACTOR_PSNR	(10.0 / log(10.0))	// for good computation
#define CALC_PSNR(w, h, s)	((float)(CONST_FACTOR_PSNR * log( 65025.0 * w * h / iSqe )))
#endif//CALC_PSNR

/*
 *	PSNR calculation routines
 */
/*!
 *************************************************************************************
 * \brief	PSNR calculation utilization in Wels
 *
 * \param	pTarPic		target picture to be calculated in Picture pData format
 * \param	iTarStride	stride of target picture pData pBuffer
 * \param 	pRefPic		base referencing picture samples
 * \param	iRefStride	stride of reference picture pData pBuffer
 * \param	iWidth		picture iWidth in pixel
 * \param	iHeight		picture iHeight in pixel
 *
 * \return	actual PSNR result;
 *
 * \note	N/A
 *************************************************************************************
 */
float WelsCalcPsnr (const void* kpTarPic,
                    const int32_t kiTarStride,
                    const void* kpRefPic,
                    const int32_t kiRefStride,
                    const int32_t kiWidth,
                    const int32_t kiHeight) {
  int64_t	iSqe = 0;
  int32_t x, y;
  uint8_t* pTar = (uint8_t*)kpTarPic;
  uint8_t* pRef = (uint8_t*)kpRefPic;

  if (NULL == pTar || NULL == pRef)
    return (-1.0f);

  for (y = 0; y < kiHeight; ++ y) {	// OPTable !!
    for (x = 0; x < kiWidth; ++ x) {
      const int32_t kiT = pTar[y * kiTarStride + x] - pRef[y * kiRefStride + x];
      iSqe	+= kiT * kiT;
    }
  }
  if (0 == iSqe) {
    return (99.99f);
  }
  return CALC_PSNR (kiWidth, kiHeight, iSqe);
}

<|endoftext|>


<commit_before>#include "layouter.h"

#include "utf-8.h"

#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>

#include <fribidi/fribidi.h>

#include <linebreak.h>

#include <vector>
#include <string>
#include <memory>
#include <algorithm>

typedef struct
{
  std::vector<textLayout_c::commandData> run;
  int dx, dy;
  FriBidiLevel embeddingLevel;
  char linebreak;
  std::shared_ptr<fontFace_c> font;
} runInfo;

// TODO create a sharing structure, where we only
// define structures for each configuration once
// and link to it
// but for now it is good as it is
typedef struct
{
  uint8_t r, g, b;
  std::shared_ptr<fontFace_c> font;
  std::string lang;
} codepointAttributes;

FriBidiLevel getBidiEmbeddingLevels(const std::u32string & txt32, std::vector<FriBidiLevel> & embedding_levels)
{
  std::vector<FriBidiCharType> bidiTypes(txt32.length());
  fribidi_get_bidi_types((uint32_t*)txt32.c_str(), txt32.length(), bidiTypes.data());
  FriBidiParType base_dir = FRIBIDI_TYPE_LTR_VAL; // TODO depends on main script of text
  embedding_levels.resize(txt32.length());
  FriBidiLevel max_level = fribidi_get_par_embedding_levels(bidiTypes.data(), txt32.length(),
                                                            &base_dir, embedding_levels.data());

  return max_level;
}

textLayout_c layoutParagraph(const std::u32string & txt32, const std::vector<codepointAttributes> & attr,
                             const shape_c & shape, const std::string & align)
{
  // calculate embedding types for the text
  std::vector<FriBidiLevel> embedding_levels;
  FriBidiLevel max_level = getBidiEmbeddingLevels(txt32, embedding_levels);

  // calculate the possible linebreak positions
  std::vector<char> linebreaks(txt32.length());
  set_linebreaks_utf32((utf32_t*)txt32.c_str(), txt32.length(), "", linebreaks.data());

  // Get our harfbuzz font structs, TODO we need to do that for all the fonts
  std::map<const std::shared_ptr<fontFace_c>, hb_font_t *> hb_ft_fonts;

  for (const auto & a : attr)
  {
    if (hb_ft_fonts.find(a.font) == hb_ft_fonts.end())
    {
      hb_ft_fonts[a.font] = hb_ft_font_create(a.font->getFace(), NULL);
    }
  }

  // Create a buffer for harfbuzz to use
  hb_buffer_t *buf = hb_buffer_create();

  std::string lan = attr[0].lang.substr(0, 2);
  std::string s = attr[0].lang.substr(3, 4);

  hb_script_t scr = hb_script_from_iso15924_tag(HB_TAG(s[0], s[1], s[2], s[3]));
  hb_buffer_set_script(buf, scr);
  // TODO must come either from text or from rules
  hb_buffer_set_language(buf, hb_language_from_string(lan.c_str(), lan.length()));

  size_t runstart = 0;

  std::vector<runInfo> runs;

  while (runstart < txt32.length())
  {
    size_t spos = runstart+1;
    // find end of current run
    while (   (spos < txt32.length())
           && (embedding_levels[runstart] == embedding_levels[spos])
           && (attr[runstart].font == attr[spos].font)
           && (   (linebreaks[spos-1] == LINEBREAK_NOBREAK)
               || (linebreaks[spos-1] == LINEBREAK_INSIDEACHAR)
              )
          )
    {
      spos++;
    }

    hb_buffer_add_utf32(buf, ((uint32_t*)txt32.c_str())+runstart, spos-runstart, 0, spos-runstart);

    if (embedding_levels[runstart] % 2 == 0)
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
    }
    else
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_RTL);
    }

    hb_shape(hb_ft_fonts[attr[runstart].font], buf, NULL, 0);

    unsigned int         glyph_count;
    hb_glyph_info_t     *glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
    hb_glyph_position_t *glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);

    runInfo run;

    run.dx = run.dy = 0;
    run.embeddingLevel = embedding_levels[runstart];
    run.linebreak = linebreaks[spos-1];
    run.font = attr[runstart].font;

    for (size_t j=0; j < glyph_count; ++j)
    {
      textLayout_c::commandData g;

      g.glyphIndex = glyph_info[j].codepoint;
      g.font = attr[runstart].font;
      // TODO the other parameters

      g.x = run.dx + (glyph_pos[j].x_offset/64);
      g.y = run.dy - (glyph_pos[j].y_offset/64);

      run.dx += glyph_pos[j].x_advance/64;
      run.dy -= glyph_pos[j].y_advance/64;

      g.r = attr[glyph_info[j].cluster + runstart].r;
      g.g = attr[glyph_info[j].cluster + runstart].g;
      g.b = attr[glyph_info[j].cluster + runstart].b;

      g.command = textLayout_c::commandData::CMD_GLYPH;

      run.run.push_back(g);
    }

    runs.push_back(run);
    runstart = spos;

    hb_buffer_reset(buf);
  }

  hb_buffer_destroy(buf);

  for (auto & a : hb_ft_fonts)
    hb_font_destroy(a.second);

  std::vector<size_t> runorder(runs.size());
  int n(0);
  std::generate(runorder.begin(), runorder.end(), [&]{ return n++; });

  // layout a run
  // TODO take care of different font sizes of the different runs
  runstart = 0;
  int32_t ypos = 0;
  textLayout_c l;

  while (runstart < runs.size())
  {
    int32_t curAscend = runs[runstart].font->getAscender()/64;
    int32_t curDescend = runs[runstart].font->getDescender()/64;
    uint32_t curWidth = runs[runstart].dx;
    size_t spos = runstart + 1;

    while (spos < runs.size())
    {
      // check, if we can add another span
      int32_t newAscend = std::max(curAscend, runs[spos].font->getAscender()/64);
      int32_t newDescend = std::min(curDescend, runs[spos].font->getDescender()/64);
      uint32_t newWidth = curWidth + runs[spos].dx;

      if (shape.getLeft(ypos, ypos+newAscend-newDescend)+newWidth >
          shape.getRight(ypos, ypos+newAscend-newDescend))
      {
        // next run would overrun
        break;
      }

      // additional run fits
      curAscend = newAscend;
      curDescend = newDescend;
      curWidth = newWidth;
      spos++;
    }

    // reorder runs for current line
    for (int i = max_level-1; i >= 0; i--)
    {
      // find starts of regions to reverse
      for (size_t j = runstart; j < spos; j++)
      {
        if (runs[runorder[j]].embeddingLevel > i)
        {
          // find the end of the current regions
          size_t k = j+1;
          while (k < spos && runs[runorder[k]].embeddingLevel > i)
          {
            k++;
          }

          std::reverse(runorder.begin()+j, runorder.begin()+k);
          j = k;
        }
      }
    }

    int32_t spaceLeft = shape.getRight(ypos, ypos+curAscend-curDescend) -
                        shape.getLeft(ypos, ypos+curAscend-curDescend);
    spaceLeft -= curWidth;

    int32_t xpos;
    double spaceadder = 0;

    if (align == "left")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
    }
    else if (align == "right")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft;
    }
    else if (align == "center")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft/2;
    }
    else if (align == "justify")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
      // don't justify last paragraph
      if (spos-runstart > 1 && spos < runs.size())
        spaceadder = 1.0 * spaceLeft / (spos-runstart - 1);
    }

    ypos += curAscend;

    for (size_t i = runstart; i < spos; i++)
    {
      l.addCommandVector(runs[runorder[i]].run, xpos+spaceadder*(i-runstart), ypos);
      xpos += runs[runorder[i]].dx;
    }

    ypos -= curDescend;
    runstart = spos;
  }

  // TODO proper font handling for multiple fonts in a line
  l.setHeight(ypos);

  return l;
}

void layoutXML_text(const pugi::xml_node & xml, const textStyleSheet_c & rules, std::u32string & txt,
               std::vector<codepointAttributes> & attr)
{
  for (const auto & i : xml)
  {
    if (i.type() == pugi::node_pcdata)
    {
      txt += u8_convertToU32(i.value());

      codepointAttributes a;

      evalColor(rules.getValue(xml, "color"), a.r, a.g, a.b);
      std::string fontFamily = rules.getValue(xml, "font-family");
      std::string fontStyle = rules.getValue(xml, "font-style");
      std::string fontVariant = rules.getValue(xml, "font-variant");
      std::string fontWeight = rules.getValue(xml, "font-weight");
      double fontSize = evalSize(rules.getValue(xml, "font-size"));

      a.font = rules.findFamily(fontFamily)->getFont(64*fontSize, fontStyle, fontVariant, fontWeight);
      a.lang = "en-eng";

      while (attr.size() < txt.length())
        attr.push_back(a);
    }
    else if (i.type() == pugi::node_element && std::string("i") == i.name())
    {
      layoutXML_text(i, rules, txt, attr);
    }
    else if (i.type() == pugi::node_element && std::string("div") == i.name())
    {
      layoutXML_text(i, rules, txt, attr);
    }
  }
}

// this whole stuff is a recursive descending parser of the XHTML stuff
textLayout_c layoutXML_P(const pugi::xml_node & xml, const textStyleSheet_c & rules, const shape_c & shape)
{
  std::u32string txt;
  std::vector<codepointAttributes> attr;

  layoutXML_text(xml, rules, txt, attr);

  return layoutParagraph(txt, attr, shape, rules.getValue(xml, "text-align"));
}

textLayout_c layoutXML_BODY(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  for (const auto & i : txt)
  {
    if (   (i.type() == pugi::node_element)
        && (   (std::string("p") == i.name())
            || (std::string("h1") == i.name())
            || (std::string("h2") == i.name())
            || (std::string("h3") == i.name())
            || (std::string("h4") == i.name())
            || (std::string("h5") == i.name())
            || (std::string("h6") == i.name())
           )
       )
    {
      l.append(layoutXML_P(i, rules, shape), 0, l.getHeight());
    }
    else if (i.type() == pugi::node_element && std::string("table") == i.name())
    {
    }
    else
    {
      // TODO exception nothing else supported
    }
  }

  return l;
}

textLayout_c layoutXML_HTML(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  bool headfound = false;
  bool bodyfound = false;

  for (const auto & i : txt)
  {
    if (std::string("head") == i.name() && !headfound)
    {
      headfound = true;
    }
    else if (std::string("body") == i.name() && !bodyfound)
    {
      bodyfound = true;
      l = layoutXML_BODY(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXML(const pugi::xml_document & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  // we must have a HTML root node
  for (const auto & i : txt)
  {
    if (std::string("html") == i.name())
    {
      l = layoutXML_HTML(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXHTML(const std::string & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  pugi::xml_document doc;
  // TODO handle parser errors
  doc.load_buffer(txt.c_str(), txt.length());
  return layoutXML(doc, rules, shape);
}

textLayout_c layoutRaw(const std::string & txt, const std::shared_ptr<fontFace_c> font, const shape_c & shape, const std::string & language)
{
  // when we layout raw text we
  // only have to convert the text to utf-32
  // and assign the given font and language to all the codepoints of that text

  std::u32string txt32 = u8_convertToU32(txt);
  std::vector<codepointAttributes> attr(txt32.size());

  for (auto & i : attr)
  {
    i.r = i.g = i.b = 255;
    i.font = font;
    i.lang = language;
  }

  return layoutParagraph(txt32, attr, shape, "left");
}
<commit_msg>add some comments TODO<commit_after>#include "layouter.h"

#include "utf-8.h"

#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>

#include <fribidi/fribidi.h>

#include <linebreak.h>

#include <vector>
#include <string>
#include <memory>
#include <algorithm>

typedef struct
{
  std::vector<textLayout_c::commandData> run;
  int dx, dy;
  FriBidiLevel embeddingLevel;
  char linebreak;
  std::shared_ptr<fontFace_c> font;
} runInfo;

// TODO create a sharing structure, where we only
// define structures for each configuration once
// and link to it
// but for now it is good as it is
typedef struct
{
  uint8_t r, g, b;
  std::shared_ptr<fontFace_c> font;
  std::string lang;
} codepointAttributes;

FriBidiLevel getBidiEmbeddingLevels(const std::u32string & txt32, std::vector<FriBidiLevel> & embedding_levels)
{
  std::vector<FriBidiCharType> bidiTypes(txt32.length());
  fribidi_get_bidi_types((uint32_t*)txt32.c_str(), txt32.length(), bidiTypes.data());
  FriBidiParType base_dir = FRIBIDI_TYPE_LTR_VAL; // TODO depends on main script of text
  embedding_levels.resize(txt32.length());
  FriBidiLevel max_level = fribidi_get_par_embedding_levels(bidiTypes.data(), txt32.length(),
                                                            &base_dir, embedding_levels.data());

  return max_level;
}

textLayout_c layoutParagraph(const std::u32string & txt32, const std::vector<codepointAttributes> & attr,
                             const shape_c & shape, const std::string & align)
{
  // calculate embedding types for the text
  std::vector<FriBidiLevel> embedding_levels;
  FriBidiLevel max_level = getBidiEmbeddingLevels(txt32, embedding_levels);

  // calculate the possible linebreak positions
  std::vector<char> linebreaks(txt32.length());
  set_linebreaks_utf32((utf32_t*)txt32.c_str(), txt32.length(), "", linebreaks.data());

  // Get our harfbuzz font structs, TODO we need to do that for all the fonts
  std::map<const std::shared_ptr<fontFace_c>, hb_font_t *> hb_ft_fonts;

  for (const auto & a : attr)
  {
    if (hb_ft_fonts.find(a.font) == hb_ft_fonts.end())
    {
      hb_ft_fonts[a.font] = hb_ft_font_create(a.font->getFace(), NULL);
    }
  }

  // Create a buffer for harfbuzz to use
  hb_buffer_t *buf = hb_buffer_create();

  std::string lan = attr[0].lang.substr(0, 2);
  std::string s = attr[0].lang.substr(3, 4);

  hb_script_t scr = hb_script_from_iso15924_tag(HB_TAG(s[0], s[1], s[2], s[3]));
  hb_buffer_set_script(buf, scr);
  // TODO must come either from text or from rules
  hb_buffer_set_language(buf, hb_language_from_string(lan.c_str(), lan.length()));

  size_t runstart = 0;

  std::vector<runInfo> runs;

  while (runstart < txt32.length())
  {
    size_t spos = runstart+1;
    // find end of current run
    while (   (spos < txt32.length())
           && (embedding_levels[runstart] == embedding_levels[spos])
           && (attr[runstart].font == attr[spos].font)
           && (   (linebreaks[spos-1] == LINEBREAK_NOBREAK)
               || (linebreaks[spos-1] == LINEBREAK_INSIDEACHAR)
              )
          )
    {
      spos++;
    }

    hb_buffer_add_utf32(buf, ((uint32_t*)txt32.c_str())+runstart, spos-runstart, 0, spos-runstart);

    if (embedding_levels[runstart] % 2 == 0)
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
    }
    else
    {
      hb_buffer_set_direction(buf, HB_DIRECTION_RTL);
    }

    hb_shape(hb_ft_fonts[attr[runstart].font], buf, NULL, 0);

    unsigned int         glyph_count;
    hb_glyph_info_t     *glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
    hb_glyph_position_t *glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);

    runInfo run;

    run.dx = run.dy = 0;
    run.embeddingLevel = embedding_levels[runstart];
    run.linebreak = linebreaks[spos-1];
    run.font = attr[runstart].font;

    for (size_t j=0; j < glyph_count; ++j)
    {
      textLayout_c::commandData g;

      g.glyphIndex = glyph_info[j].codepoint;
      g.font = attr[runstart].font;
      // TODO the other parameters

      g.x = run.dx + (glyph_pos[j].x_offset/64);
      g.y = run.dy - (glyph_pos[j].y_offset/64);

      run.dx += glyph_pos[j].x_advance/64;
      run.dy -= glyph_pos[j].y_advance/64;

      g.r = attr[glyph_info[j].cluster + runstart].r;
      g.g = attr[glyph_info[j].cluster + runstart].g;
      g.b = attr[glyph_info[j].cluster + runstart].b;

      g.command = textLayout_c::commandData::CMD_GLYPH;

      run.run.push_back(g);
    }

    runs.push_back(run);
    runstart = spos;

    hb_buffer_reset(buf);
  }

  hb_buffer_destroy(buf);

  for (auto & a : hb_ft_fonts)
    hb_font_destroy(a.second);

  std::vector<size_t> runorder(runs.size());
  int n(0);
  std::generate(runorder.begin(), runorder.end(), [&]{ return n++; });

  // layout a run
  // TODO take care of different font sizes of the different runs
  runstart = 0;
  int32_t ypos = 0;
  textLayout_c l;

  while (runstart < runs.size())
  {
    int32_t curAscend = runs[runstart].font->getAscender()/64;
    int32_t curDescend = runs[runstart].font->getDescender()/64;
    uint32_t curWidth = runs[runstart].dx;
    size_t spos = runstart + 1;

    while (spos < runs.size())
    {
      // check, if we can add another run
      // TODO keep non break runs in mind
      // TODO take properly care of spaces at the end of lines (they must be left out)
      int32_t newAscend = std::max(curAscend, runs[spos].font->getAscender()/64);
      int32_t newDescend = std::min(curDescend, runs[spos].font->getDescender()/64);
      uint32_t newWidth = curWidth + runs[spos].dx;

      if (shape.getLeft(ypos, ypos+newAscend-newDescend)+newWidth >
          shape.getRight(ypos, ypos+newAscend-newDescend))
      {
        // next run would overrun
        break;
      }

      // additional run fits
      curAscend = newAscend;
      curDescend = newDescend;
      curWidth = newWidth;
      spos++;
    }

    // reorder runs for current line
    for (int i = max_level-1; i >= 0; i--)
    {
      // find starts of regions to reverse
      for (size_t j = runstart; j < spos; j++)
      {
        if (runs[runorder[j]].embeddingLevel > i)
        {
          // find the end of the current regions
          size_t k = j+1;
          while (k < spos && runs[runorder[k]].embeddingLevel > i)
          {
            k++;
          }

          std::reverse(runorder.begin()+j, runorder.begin()+k);
          j = k;
        }
      }
    }

    int32_t spaceLeft = shape.getRight(ypos, ypos+curAscend-curDescend) -
                        shape.getLeft(ypos, ypos+curAscend-curDescend);
    spaceLeft -= curWidth;

    int32_t xpos;
    double spaceadder = 0;

    if (align == "left")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
    }
    else if (align == "right")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft;
    }
    else if (align == "center")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend) + spaceLeft/2;
    }
    else if (align == "justify")
    {
      xpos = shape.getLeft(ypos, ypos+curAscend-curDescend);
      // don't justify last paragraph
      if (spos-runstart > 1 && spos < runs.size())
        spaceadder = 1.0 * spaceLeft / (spos-runstart - 1);
    }

    ypos += curAscend;

    for (size_t i = runstart; i < spos; i++)
    {
      l.addCommandVector(runs[runorder[i]].run, xpos+spaceadder*(i-runstart), ypos);
      xpos += runs[runorder[i]].dx;
    }

    ypos -= curDescend;
    runstart = spos;
  }

  // TODO proper font handling for multiple fonts in a line
  l.setHeight(ypos);

  return l;
}

void layoutXML_text(const pugi::xml_node & xml, const textStyleSheet_c & rules, std::u32string & txt,
               std::vector<codepointAttributes> & attr)
{
  for (const auto & i : xml)
  {
    if (i.type() == pugi::node_pcdata)
    {
      txt += u8_convertToU32(i.value());

      codepointAttributes a;

      evalColor(rules.getValue(xml, "color"), a.r, a.g, a.b);
      std::string fontFamily = rules.getValue(xml, "font-family");
      std::string fontStyle = rules.getValue(xml, "font-style");
      std::string fontVariant = rules.getValue(xml, "font-variant");
      std::string fontWeight = rules.getValue(xml, "font-weight");
      double fontSize = evalSize(rules.getValue(xml, "font-size"));

      a.font = rules.findFamily(fontFamily)->getFont(64*fontSize, fontStyle, fontVariant, fontWeight);
      a.lang = "en-eng";

      while (attr.size() < txt.length())
        attr.push_back(a);
    }
    else if (i.type() == pugi::node_element && std::string("i") == i.name())
    {
      layoutXML_text(i, rules, txt, attr);
    }
    else if (i.type() == pugi::node_element && std::string("div") == i.name())
    {
      layoutXML_text(i, rules, txt, attr);
    }
  }
}

// this whole stuff is a recursive descending parser of the XHTML stuff
textLayout_c layoutXML_P(const pugi::xml_node & xml, const textStyleSheet_c & rules, const shape_c & shape)
{
  std::u32string txt;
  std::vector<codepointAttributes> attr;

  layoutXML_text(xml, rules, txt, attr);

  return layoutParagraph(txt, attr, shape, rules.getValue(xml, "text-align"));
}

textLayout_c layoutXML_BODY(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  for (const auto & i : txt)
  {
    if (   (i.type() == pugi::node_element)
        && (   (std::string("p") == i.name())
            || (std::string("h1") == i.name())
            || (std::string("h2") == i.name())
            || (std::string("h3") == i.name())
            || (std::string("h4") == i.name())
            || (std::string("h5") == i.name())
            || (std::string("h6") == i.name())
           )
       )
    {
      // TODO rahmen und anderes beachten
      l.append(layoutXML_P(i, rules, shape), 0, l.getHeight());
    }
    else if (i.type() == pugi::node_element && std::string("table") == i.name())
    {
    }
    else
    {
      // TODO exception nothing else supported
    }
  }

  return l;
}

textLayout_c layoutXML_HTML(const pugi::xml_node & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  bool headfound = false;
  bool bodyfound = false;

  for (const auto & i : txt)
  {
    if (std::string("head") == i.name() && !headfound)
    {
      headfound = true;
    }
    else if (std::string("body") == i.name() && !bodyfound)
    {
      bodyfound = true;
      l = layoutXML_BODY(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXML(const pugi::xml_document & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  textLayout_c l;

  // we must have a HTML root node
  for (const auto & i : txt)
  {
    if (std::string("html") == i.name())
    {
      l = layoutXML_HTML(i, rules, shape);
    }
    else
    {
      // nothing else permitted -> exception TODO
    }
  }

  return l;
}

textLayout_c layoutXHTML(const std::string & txt, const textStyleSheet_c & rules, const shape_c & shape)
{
  pugi::xml_document doc;
  // TODO preprocess to get rid of linebreaks and multiple spaces

  // TODO handle parser errors
  doc.load_buffer(txt.c_str(), txt.length());
  return layoutXML(doc, rules, shape);
}

textLayout_c layoutRaw(const std::string & txt, const std::shared_ptr<fontFace_c> font, const shape_c & shape, const std::string & language)
{
  // when we layout raw text we
  // only have to convert the text to utf-32
  // and assign the given font and language to all the codepoints of that text

  std::u32string txt32 = u8_convertToU32(txt);
  std::vector<codepointAttributes> attr(txt32.size());

  for (auto & i : attr)
  {
    i.r = i.g = i.b = 255;
    i.font = font;
    i.lang = language;
  }

  return layoutParagraph(txt32, attr, shape, "left");
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ContextHelper.cxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: bm $ $Date: 2003-10-06 09:58:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source 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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2003 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#include "ContextHelper.hxx"
#include <cppuhelper/component_context.hxx>

#include <vector>

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

namespace chart
{

namespace ContextHelper
{

uno::Reference< uno::XComponentContext >
    createContext(
        const tContextEntryMapType & rMap,
        const uno::Reference< uno::XComponentContext > & rDelegateContext )
{
    ::std::vector< ::cppu::ContextEntry_Init > aVec( rMap.size());
    for( tContextEntryMapType::const_iterator aIt = rMap.begin();
         aIt != rMap.end();
         ++aIt )
    {
        aVec.push_back( ::cppu::ContextEntry_Init( (*aIt).first, (*aIt).second) );
    }

    return ::cppu::createComponentContext( & aVec[0], aVec.size(), rDelegateContext );
}

} //  namespace ContextHelper

} //  namespace chart
<commit_msg>INTEGRATION: CWS ooo19126 (1.1.1.1.110); FILE MERGED 2005/09/05 18:43:29 rt 1.1.1.1.110.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ContextHelper.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 01:27:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include "ContextHelper.hxx"
#include <cppuhelper/component_context.hxx>

#include <vector>

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

namespace chart
{

namespace ContextHelper
{

uno::Reference< uno::XComponentContext >
    createContext(
        const tContextEntryMapType & rMap,
        const uno::Reference< uno::XComponentContext > & rDelegateContext )
{
    ::std::vector< ::cppu::ContextEntry_Init > aVec( rMap.size());
    for( tContextEntryMapType::const_iterator aIt = rMap.begin();
         aIt != rMap.end();
         ++aIt )
    {
        aVec.push_back( ::cppu::ContextEntry_Init( (*aIt).first, (*aIt).second) );
    }

    return ::cppu::createComponentContext( & aVec[0], aVec.size(), rDelegateContext );
}

} //  namespace ContextHelper

} //  namespace chart
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

#include "expenses.hpp"
#include "args.hpp"
#include "accounts.hpp"
#include "data.hpp"
#include "guid.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "console.hpp"
#include "budget_exception.hpp"

using namespace budget;

namespace {

static data_handler<expense> expenses;

void show_expenses(boost::gregorian::greg_month month, boost::gregorian::greg_year year){
    std::vector<std::string> columns = {"ID", "Date", "Account", "Name", "Amount"};
    std::vector<std::vector<std::string>> contents;

    money total;
    std::size_t count = 0;

    for(auto& expense : expenses.data){
        if(expense.date.year() == year && expense.date.month() == month){
            contents.push_back({to_string(expense.id), to_string(expense.date), get_account(expense.account).name, expense.name, to_string(expense.amount)});

            total += expense.amount;
            ++count;
        }
    }

    if(count == 0){
        std::cout << "No expenses for " << month << "-" << year << std::endl;
    } else {
        contents.push_back({"", "", "", "Total", to_string(total)});

        display_table(columns, contents);
    }
}

void show_expenses(boost::gregorian::greg_month month){
    auto today = boost::gregorian::day_clock::local_day();

    show_expenses(month, today.year());
}

void show_expenses(){
    auto today = boost::gregorian::day_clock::local_day();

    show_expenses(today.month(), today.year());
}

void show_all_expenses(){
    std::vector<std::string> columns = {"ID", "Date", "Account", "Name", "Amount"};
    std::vector<std::vector<std::string>> contents;

    for(auto& expense : expenses.data){
        contents.push_back({to_string(expense.id), to_string(expense.date), get_account(expense.account).name, expense.name, to_string(expense.amount)});
    }

    display_table(columns, contents);
}

} //end of anonymous namespace

void budget::expenses_module::load(){
    load_expenses();
    load_accounts();
}

void budget::expenses_module::unload(){
    save_expenses();
}

void budget::expenses_module::handle(const std::vector<std::string>& args){
    if(args.size() == 1){
        show_expenses();
    } else {
        auto& subcommand = args[1];

        if(subcommand == "show"){
            if(args.size() == 2){
                show_expenses();
            } else if(args.size() == 3){
                show_expenses(boost::gregorian::greg_month(to_number<unsigned short>(args[2])));
            } else if(args.size() == 4){
                show_expenses(
                    boost::gregorian::greg_month(to_number<unsigned short>(args[2])),
                    boost::gregorian::greg_year(to_number<unsigned short>(args[3])));
            } else {
                throw budget_exception("Too many arguments to expense show");
            }
        } else if(subcommand == "all"){
            show_all_expenses();
        } else if(subcommand == "add"){
            enough_args(args, 5);

            expense expense;
            expense.guid = generate_guid();
            expense.date = boost::gregorian::day_clock::local_day();

            auto account_name = args[2];
            validate_account(account_name);
            expense.account = get_account(account_name).id;

            expense.amount = parse_money(args[3]);
            not_negative(expense.amount);

            for(std::size_t i = 4; i < args.size(); ++i){
                expense.name += args[i] + " ";
            }

            add_data(expenses, std::move(expense));
        } else if(subcommand == "addd"){
            enough_args(args, 6);

            expense expense;
            expense.guid = generate_guid();
            expense.date = boost::gregorian::from_string(args[2]);

            auto account_name = args[3];
            validate_account(account_name);
            expense.account = get_account(account_name).id;

            expense.amount = parse_money(args[4]);
            not_negative(expense.amount);

            for(std::size_t i = 5; i < args.size(); ++i){
                expense.name += args[i] + " ";
            }

            add_data(expenses, std::move(expense));
        } else if(subcommand == "delete"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(expenses, id)){
                throw budget_exception("There are no expense with id ");
            }

            remove(expenses, id);

            std::cout << "Expense " << id << " has been deleted" << std::endl;
        } else if(subcommand == "edit"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(expenses, id)){
                throw budget_exception("There are no expense with id " + args[2]);
            }

            auto& expense = get(expenses, id);

            edit_date(expense.date, "Date");

            auto account_name = get_account(expense.account).name;
            edit_string(account_name, "Account");
            validate_account(account_name);
            expense.account = get_account(account_name).id;

            edit_string(expense.name, "Name");
            edit_money(expense.amount, "Amount");

            std::cout << "Expense " << id << " has been modified" << std::endl;
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}

void budget::load_expenses(){
    load_data(expenses, "expenses.data");
}

void budget::save_expenses(){
    save_data(expenses, "expenses.data");
}

void budget::add_expense(budget::expense&& expense){
    add_data(expenses, std::forward<budget::expense>(expense));
}

std::ostream& budget::operator<<(std::ostream& stream, const expense& expense){
    return stream << expense.id  << ':' << expense.guid << ':' << expense.account << ':' << expense.name << ':' << expense.amount << ':' << to_string(expense.date);
}

void budget::operator>>(const std::vector<std::string>& parts, expense& expense){
    expense.id = to_number<std::size_t>(parts[0]);
    expense.guid = parts[1];
    expense.account = to_number<std::size_t>(parts[2]);
    expense.name = parts[3];
    expense.amount = parse_money(parts[4]);
    expense.date = boost::gregorian::from_string(parts[5]);
}

std::vector<expense>& budget::all_expenses(){
    return expenses.data;
}
<commit_msg>Implement a better way to create expenses<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

#include "expenses.hpp"
#include "args.hpp"
#include "accounts.hpp"
#include "data.hpp"
#include "guid.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "console.hpp"
#include "budget_exception.hpp"

using namespace budget;

namespace {

static data_handler<expense> expenses;

void show_expenses(boost::gregorian::greg_month month, boost::gregorian::greg_year year){
    std::vector<std::string> columns = {"ID", "Date", "Account", "Name", "Amount"};
    std::vector<std::vector<std::string>> contents;

    money total;
    std::size_t count = 0;

    for(auto& expense : expenses.data){
        if(expense.date.year() == year && expense.date.month() == month){
            contents.push_back({to_string(expense.id), to_string(expense.date), get_account(expense.account).name, expense.name, to_string(expense.amount)});

            total += expense.amount;
            ++count;
        }
    }

    if(count == 0){
        std::cout << "No expenses for " << month << "-" << year << std::endl;
    } else {
        contents.push_back({"", "", "", "Total", to_string(total)});

        display_table(columns, contents);
    }
}

void show_expenses(boost::gregorian::greg_month month){
    auto today = boost::gregorian::day_clock::local_day();

    show_expenses(month, today.year());
}

void show_expenses(){
    auto today = boost::gregorian::day_clock::local_day();

    show_expenses(today.month(), today.year());
}

void show_all_expenses(){
    std::vector<std::string> columns = {"ID", "Date", "Account", "Name", "Amount"};
    std::vector<std::vector<std::string>> contents;

    for(auto& expense : expenses.data){
        contents.push_back({to_string(expense.id), to_string(expense.date), get_account(expense.account).name, expense.name, to_string(expense.amount)});
    }

    display_table(columns, contents);
}

void validate_name(const std::string& name){
    if(name.empty()){
        throw budget_exception("The name of the expense cannot be empty");
    }
}

} //end of anonymous namespace

void budget::expenses_module::load(){
    load_expenses();
    load_accounts();
}

void budget::expenses_module::unload(){
    save_expenses();
}

void budget::expenses_module::handle(const std::vector<std::string>& args){
    if(args.size() == 1){
        show_expenses();
    } else {
        auto& subcommand = args[1];

        if(subcommand == "show"){
            if(args.size() == 2){
                show_expenses();
            } else if(args.size() == 3){
                show_expenses(boost::gregorian::greg_month(to_number<unsigned short>(args[2])));
            } else if(args.size() == 4){
                show_expenses(
                    boost::gregorian::greg_month(to_number<unsigned short>(args[2])),
                    boost::gregorian::greg_year(to_number<unsigned short>(args[3])));
            } else {
                throw budget_exception("Too many arguments to expense show");
            }
        } else if(subcommand == "all"){
            show_all_expenses();
        } else if(subcommand == "add"){
            if(args.size() == 2){
                expense expense;
                expense.guid = generate_guid();
                expense.date = boost::gregorian::day_clock::local_day();

                edit_date(expense.date, "Date");

                std::string account_name;
                edit_string(account_name, "Account");
                validate_account(account_name);
                expense.account = get_account(account_name).id;

                edit_string(expense.name, "Name");
                validate_name(expense.name);

                edit_money(expense.amount, "Amount");
                not_negative(expense.amount);

                add_data(expenses, std::move(expense));
            } else {
                enough_args(args, 5);

                expense expense;
                expense.guid = generate_guid();
                expense.date = boost::gregorian::day_clock::local_day();

                auto account_name = args[2];
                validate_account(account_name);
                expense.account = get_account(account_name).id;

                expense.amount = parse_money(args[3]);
                not_negative(expense.amount);

                for(std::size_t i = 4; i < args.size(); ++i){
                    expense.name += args[i] + " ";
                }

                validate_name(expense.name);

                add_data(expenses, std::move(expense));
            }
        } else if(subcommand == "addd"){
            enough_args(args, 6);

            expense expense;
            expense.guid = generate_guid();
            expense.date = boost::gregorian::from_string(args[2]);

            auto account_name = args[3];
            validate_account(account_name);
            expense.account = get_account(account_name).id;

            expense.amount = parse_money(args[4]);
            not_negative(expense.amount);

            for(std::size_t i = 5; i < args.size(); ++i){
                expense.name += args[i] + " ";
            }

            validate_name(expense.name);

            add_data(expenses, std::move(expense));
        } else if(subcommand == "delete"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(expenses, id)){
                throw budget_exception("There are no expense with id ");
            }

            remove(expenses, id);

            std::cout << "Expense " << id << " has been deleted" << std::endl;
        } else if(subcommand == "edit"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(expenses, id)){
                throw budget_exception("There are no expense with id " + args[2]);
            }

            auto& expense = get(expenses, id);

            edit_date(expense.date, "Date");

            auto account_name = get_account(expense.account).name;
            edit_string(account_name, "Account");
            validate_account(account_name);
            expense.account = get_account(account_name).id;

            edit_string(expense.name, "Name");
            validate_name(expense.name);

            edit_money(expense.amount, "Amount");
            not_negative(expense.amount);

            std::cout << "Expense " << id << " has been modified" << std::endl;
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}

void budget::load_expenses(){
    load_data(expenses, "expenses.data");
}

void budget::save_expenses(){
    save_data(expenses, "expenses.data");
}

void budget::add_expense(budget::expense&& expense){
    add_data(expenses, std::forward<budget::expense>(expense));
}

std::ostream& budget::operator<<(std::ostream& stream, const expense& expense){
    return stream << expense.id  << ':' << expense.guid << ':' << expense.account << ':' << expense.name << ':' << expense.amount << ':' << to_string(expense.date);
}

void budget::operator>>(const std::vector<std::string>& parts, expense& expense){
    expense.id = to_number<std::size_t>(parts[0]);
    expense.guid = parts[1];
    expense.account = to_number<std::size_t>(parts[2]);
    expense.name = parts[3];
    expense.amount = parse_money(parts[4]);
    expense.date = boost::gregorian::from_string(parts[5]);
}

std::vector<expense>& budget::all_expenses(){
    return expenses.data;
}
<|endoftext|>


<commit_before>#ifndef __COMPHELPER_UNOINTERFACETOUNIQUEIDENTIFIERMAPPER__
#define __COMPHELPER_UNOINTERFACETOUNIQUEIDENTIFIERMAPPER__

#include <map>

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_XINTERFACE_HPP_
#include <com/sun/star/uno/XInterface.hpp>
#endif

namespace comphelper
{

typedef ::std::map< rtl::OUString, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > IdMap_t;

class UnoInterfaceToUniqueIdentifierMapper
{
public:
    UnoInterfaceToUniqueIdentifierMapper();

    /** returns a unique identifier for the given uno object. IF a uno object is
        registered more than once, the returned identifier is always the same.
    */
    const rtl::OUString& registerReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface );

    /** registers the given uno object with the given identifier.

        @returns
            false, if the given identifier already exists and is not associated with the given interface
    */
    bool registerReference( const rtl::OUString& rIdentifier, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface );

    /** @returns
            the identifier for the given uno object. If this uno object is not already
            registered, an empty string is returned
    */
    const rtl::OUString& getIdentifier( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface ) const;

    /** @returns
        the uno object that is registered with the given identifier. If no uno object
        is registered with the given identifier, an empty reference is returned.
    */
    const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& getReference( const rtl::OUString& rIdentifier ) const;

private:
    bool findReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface, IdMap_t::const_iterator& rIter ) const;
    bool findIdentifier( const rtl::OUString& rIdentifier, IdMap_t::const_iterator& rIter ) const;

    IdMap_t maEntries;
    sal_Int32 mnNextId;
};

};

#endif
<commit_msg>INTEGRATION: CWS warnings01 (1.2.224); FILE MERGED 2005/11/16 21:33:55 pl 1.2.224.1: #i55991# removed warnings<commit_after>#ifndef __COMPHELPER_UNOINTERFACETOUNIQUEIDENTIFIERMAPPER__
#define __COMPHELPER_UNOINTERFACETOUNIQUEIDENTIFIERMAPPER__

#include <map>

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_XINTERFACE_HPP_
#include <com/sun/star/uno/XInterface.hpp>
#endif

namespace comphelper
{

typedef ::std::map< rtl::OUString, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > IdMap_t;

class UnoInterfaceToUniqueIdentifierMapper
{
public:
    UnoInterfaceToUniqueIdentifierMapper();

    /** returns a unique identifier for the given uno object. IF a uno object is
        registered more than once, the returned identifier is always the same.
    */
    const rtl::OUString& registerReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface );

    /** registers the given uno object with the given identifier.

        @returns
            false, if the given identifier already exists and is not associated with the given interface
    */
    bool registerReference( const rtl::OUString& rIdentifier, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface );

    /** @returns
            the identifier for the given uno object. If this uno object is not already
            registered, an empty string is returned
    */
    const rtl::OUString& getIdentifier( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface ) const;

    /** @returns
        the uno object that is registered with the given identifier. If no uno object
        is registered with the given identifier, an empty reference is returned.
    */
    const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& getReference( const rtl::OUString& rIdentifier ) const;

private:
    bool findReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rInterface, IdMap_t::const_iterator& rIter ) const;
    bool findIdentifier( const rtl::OUString& rIdentifier, IdMap_t::const_iterator& rIter ) const;

    IdMap_t maEntries;
    sal_Int32 mnNextId;
};

}

#endif
<|endoftext|>


<commit_before>#include<iostream>
#include<fstream>
#include<string>
#include<vector>
/*to do:
	figure out what other functions might be useful
	populate datastructures.txt more, change name to something better like programming.txt or w/e
*/
struct rdnode {
	public:
	std::string topic;
	std::vector<rdnode*> parents;
	std::vector<rdnode*> children;
	bool knows;
};

struct database {
	std::vector<rdnode*> nodes;
};

void learnable (database* points) {
	rdnode* temp;
	std::vector<rdnode*> learn;
	bool learnability = true;
	for (int count = 0; count < points->nodes.size(); count++) {
		learnability = true;
		std::cout << "aaaaaa" << std::endl;
		temp = points->nodes[count];
		if (temp->knows == false) {
			rdnode* parent;
			std::cout << "aaabbbbaaa" << std::endl;
			for (int counter = temp->parents.size() - 1; counter >= 0 && learnability == true; counter--) {
				parent = temp->parents[counter];
				if (parent->knows == false) {
					learnability = false;
				}
			}
			if (learnability == true) {
				std::cout << "accca" << std::endl;
				learn.push_back(temp);
			}
		}
	}
	std::cout << "You can learn: " << learn.size() << " topics." << std::endl;
	for (int count = 0; count < learn.size(); count++) {
		temp = learn[count];
		std::cout << temp->topic << " " << std::endl;
	}
}

void depopulate(database* points) {
	rdnode* delnode;
	for (int count = 0; count < points->nodes.size(); count++) {
		delnode = points->nodes[count];
		delete delnode;
	}
	delete points;
}

rdnode* makenode(std::string topicname, database* points) {
	rdnode* tempnode;
	for (int count = 0; count < points->nodes.size(); count++) {
		tempnode = points->nodes[count];
		if (tempnode->topic == topicname) {
			return tempnode;
		}
	}
	rdnode* newnode = new rdnode;
	newnode->topic = topicname;
	newnode->knows = false;
	points->nodes.push_back(newnode);
	return newnode;
}

bool asker(rdnode* temp) {
	char answer;
	std::cout << "Do you understand " << temp->topic << " (y/n)?" << std::endl;
	std::cin >> answer;
	if (answer == 'y') {
		return true;
	}
	if (answer == 'n') {
		return false;
	}
	std::cout << "That's not y or n. Try again." << std::endl;
	return asker(temp);
}

void parentsknown(rdnode* temp) {
	temp->knows = true;
	for (int count = 0; count < temp->parents.size(); count++) {
		parentsknown(temp->parents[count]);
	}
}

void knows(database* points, bool hasfile) {
	rdnode* temp;
	bool yeah;
	std::vector<std::string> person;
	if (hasfile == true) {
		std::cout << "Enter name of student file." << std::endl;
		char filename[30];
		std::cin >> filename;
		std::ifstream inputconf(filename);
		std::string line;
		while (getline (inputconf, line)) {
			person.push_back(line);
		}
		inputconf.close();
	}
	for (int count = 0; count < points->nodes.size(); count++) {
		yeah = false;
		temp = points->nodes[count];
		if (temp->knows == false) {
			if (!hasfile) {
				temp->knows = asker(temp);
				if (temp->knows) {
					yeah = true;
				}
			}
			else {
				for (int counter = 0; counter < person.size() && yeah == false; counter++) {
					if (person[counter] == temp->topic) {
						yeah = true;
						temp->knows = true;
					}
				}
			}
			if (yeah) {
				parentsknown(temp);
			}
		}
	}
}

database* populate(database* points) {
	char filename[30];
	std::cout << "Enter file name for database." << std::endl;
	std::cin >> filename;
	std::vector<std::string> conf;
	std::ifstream inputconf(filename);
	std::string line;
	while (getline (inputconf, line)) {
		conf.push_back(line);
	}
	inputconf.close();
	for (int counter = 0; counter < conf.size(); counter++) {
		line = conf[counter];
		rdnode* tempnode;
		std::string currstring;
		int count = 0;
		std::vector<rdnode*> parenting;
		for(; count < line.size(); count++) {
			if (line[count] != ',' && line[count] != '#') {
				currstring.push_back(line[count]);
			}
			if (line[count] == ',' || line[count] == '#') {
				tempnode = makenode(currstring, points);
				currstring.clear();
				parenting.push_back(tempnode);
			}
			if (line[count] == '#') {
				break;
			}
		}
		count++;
		for (; count < line.size(); count++) {
			currstring.push_back(line[count]);
		}
		tempnode = makenode(currstring, points);
		rdnode* currentparent;
		bool add = true;
		for (count = 0; count < parenting.size(); count++) {
			currentparent = parenting[count];
			for (int counter = 0; counter < tempnode->parents.size(); counter++) {
				if (tempnode->parents[counter] == currentparent) {
					add = false;
				}
			}
			if (add == true) {
				tempnode->parents.push_back(parenting[count]);
				currentparent->children.push_back(tempnode);
			}
		}
	}
	return points;
}

void printall(database* points) {
	rdnode* temp;
	for (int count = 0; count < points->nodes.size(); count++) {
		temp = points->nodes[count];
		std::cout << temp->topic << std::endl;
	}
}

void rmknows(database* points) {
	rdnode* temp;
	for (int count = 0; count < points->nodes.size(); count++) {
		temp = points->nodes[count];
		temp->knows = false;
	}
}

void student(database* points) {
	std::cout << "Enter name of student file." << std::endl;
	std::vector<std::string> person;
	char filename[30];
	std::cin >> filename;
	std::ifstream inputconf(filename);
	std::string line;
	while (getline (inputconf, line)) {
		person.push_back(line);
	}
	inputconf.close();
	rdnode* tempnode;
	bool finishloop = false;
	for (int count = 0; count < person.size(); count++) {
		for (int counter = 0; counter < points->nodes.size() && finishloop == false; counter++) {
			tempnode = points->nodes[counter];
			if (tempnode->topic == person[count]) {
				tempnode->knows = true;
				finishloop = true;
			}
		}
		finishloop = false;
	}
}

std::vector<std::string> prerequisites(rdnode* node, database* points) {
	std::vector<std::string> needtoknow;
	rdnode* parent;
	for (int count = 0; count < node->parents.size(); count++) {
		parent = node->parents[count];
		if (parent->knows == false) {
			needtoknow.push_back(parent->topic);
			std::vector<std::string> alsoneed = prerequisites(parent, points);
			for (int counter = 0; counter < alsoneed.size(); counter++) {
				needtoknow.push_back(alsoneed[counter]);
			}
		}
	}
	return needtoknow;
}

int main() {
	database* points = new database;
	points = populate(points);
	bool keeplooping = true;
	std::cout << "Do you have a student file? (y/n)?" << std::endl;
	char answer;
	std::cin >> answer;
	if (answer == 'y') {
		knows(points, true);
	}
	else {
		std::cout << "else is working" << std::endl;
		knows(points, false);
	}
	while (keeplooping) {
		std::cout << "Your options: Change student (a), List all learnable topics for current student (b), Find out what you need to learn before you can learn a specified topic (c), Print all topics in the database (d), Remove current database and build a new database (e), Add a database's nodes to the current database (f), Exit program (g)" << std::endl;
		std::cin >> answer;
		if (answer == 'a') {
			rmknows(points);
			std::cout << "Do you have a student file? (y/n)?" << std::endl;
			char answer;
			std::cin >> answer;
			if (answer == 'y') {
				knows(points, true);
			}
			else {
				knows(points, false);
			}
		}
		if (answer == 'b') {
			learnable(points);
		}
		if (answer == 'c') {
			std::cout << "Type in the name of the topic." << std::endl;
			std::string topicname;
			std::getline (std::cin, topicname);
			rdnode* node;
			bool assigned = false;
			std::vector<std::string> gottalearn;
			for (int count = 0; count < points->nodes.size() && assigned == false; count++) {
				node = points->nodes[count];
				if (node->topic == topicname) {
					std::cout << "That topic exists in the database." << std::endl;
					assigned = true;
				}
			}
			if (assigned == false) {
				std::cout << "That topic isn't in the database. You may have spelled or formatted it incorrectly; make sure all your letters are lowercase." << std::endl;
			}
			else {
				gottalearn = prerequisites(node, points);
				if (gottalearn.size() == 0) {
					std::cout << "You can learn that now!" << std::endl;
				}
				else {
					std::cout << "You need to learn ";
					for (int count = 0; count < gottalearn.size(); count++) {
						std::cout << gottalearn[count];
						if (count + 1 < gottalearn.size()) {
							std::cout << " and";
						}
					}
					std::cout << " before you can learn " << topicname << "." << std::endl;
				}
			}
		}
		if (answer == 'd') {
			printall(points);
		}
		if (answer == 'e') {
			depopulate(points);
			database* points = populate(points);
		}
		if (answer == 'f') {
			points = populate(points);
		}
		if (answer == 'g') {
			keeplooping = false;
		}
	}
	depopulate(points);
	return 0;
}
<commit_msg>Update learning.cpp<commit_after>#include<iostream>
#include<fstream>
#include<string>
#include<vector>
/*to do:
	figure out what other functions might be useful
	populate datastructures.txt more, change name to something better like programming.txt or w/e
*/
struct rdnode {
	public:
	std::string topic;
	std::vector<rdnode*> parents;
	std::vector<rdnode*> children;
	bool knows;
};

struct database {
	std::vector<rdnode*> nodes;
};

void learnable (database* points) {
	rdnode* temp;
	std::vector<rdnode*> learn;
	bool learnability = true;
	for (int count = 0; count < points->nodes.size(); count++) {
		learnability = true;
		std::cout << "aaaaaa" << std::endl;
		temp = points->nodes[count];
		if (temp->knows == false) {
			rdnode* parent;
			std::cout << "aaabbbbaaa" << std::endl;
			for (int counter = temp->parents.size() - 1; counter >= 0 && learnability == true; counter--) {
				parent = temp->parents[counter];
				if (parent->knows == false) {
					learnability = false;
				}
			}
			if (learnability == true) {
				std::cout << "accca" << std::endl;
				learn.push_back(temp);
			}
		}
	}
	std::cout << "You can learn: " << learn.size() << " topics." << std::endl;
	for (int count = 0; count < learn.size(); count++) {
		temp = learn[count];
		std::cout << temp->topic << " " << std::endl;
	}
}

void depopulate(database* points) {
	rdnode* delnode;
	for (int count = 0; count < points->nodes.size(); count++) {
		delnode = points->nodes[count];
		delete delnode;
	}
	delete points;
}

rdnode* makenode(std::string topicname, database* points) {
	rdnode* tempnode;
	for (int count = 0; count < points->nodes.size(); count++) {
		tempnode = points->nodes[count];
		if (tempnode->topic == topicname) {
			return tempnode;
		}
	}
	rdnode* newnode = new rdnode;
	newnode->topic = topicname;
	newnode->knows = false;
	points->nodes.push_back(newnode);
	return newnode;
}

bool asker(rdnode* temp) {
	char answer;
	std::cout << "Do you understand " << temp->topic << " (y/n)?" << std::endl;
	std::cin >> answer;
	if (answer == 'y') {
		return true;
	}
	if (answer == 'n') {
		return false;
	}
	std::cout << "That's not y or n. Try again." << std::endl;
	return asker(temp);
}

void parentsknown(rdnode* temp) {
	temp->knows = true;
	for (int count = 0; count < temp->parents.size(); count++) {
		parentsknown(temp->parents[count]);
	}
}

void knows(database* points, bool hasfile) {
	rdnode* temp;
	bool yeah;
	std::vector<std::string> person;
	if (hasfile == true) {
		std::cout << "Enter name of student file." << std::endl;
		char filename[30];
		std::cin >> filename;
		std::ifstream inputconf(filename);
		std::string line;
		while (getline (inputconf, line)) {
			person.push_back(line);
		}
		inputconf.close();
	}
	for (int count = 0; count < points->nodes.size(); count++) {
		yeah = false;
		temp = points->nodes[count];
		if (temp->knows == false) {
			if (!hasfile) {
				temp->knows = asker(temp);
				if (temp->knows) {
					yeah = true;
				}
			}
			else {
				for (int counter = 0; counter < person.size() && yeah == false; counter++) {
					if (person[counter] == temp->topic) {
						yeah = true;
						temp->knows = true;
					}
				}
			}
			if (yeah) {
				parentsknown(temp);
			}
		}
	}
}

database* populate(database* points) {
	char filename[30];
	std::cout << "Enter file name for database." << std::endl;
	std::cin >> filename;
	std::vector<std::string> conf;
	std::ifstream inputconf(filename);
	std::string line;
	while (getline (inputconf, line)) {
		conf.push_back(line);
	}
	inputconf.close();
	for (int counter = 0; counter < conf.size(); counter++) {
		line = conf[counter];
		rdnode* tempnode;
		std::string currstring;
		int count = 0;
		std::vector<rdnode*> parenting;
		for(; count < line.size(); count++) {
			if (line[count] != ',' && line[count] != '#') {
				currstring.push_back(line[count]);
			}
			if (line[count] == ',' || line[count] == '#') {
				tempnode = makenode(currstring, points);
				currstring.clear();
				parenting.push_back(tempnode);
			}
			if (line[count] == '#') {
				break;
			}
		}
		count++;
		for (; count < line.size(); count++) {
			currstring.push_back(line[count]);
		}
		tempnode = makenode(currstring, points);
		rdnode* currentparent;
		bool add = true;
		for (count = 0; count < parenting.size(); count++) {
			currentparent = parenting[count];
			for (int counter = 0; counter < tempnode->parents.size(); counter++) {
				if (tempnode->parents[counter] == currentparent) {
					add = false;
				}
			}
			if (add == true) {
				tempnode->parents.push_back(parenting[count]);
				currentparent->children.push_back(tempnode);
			}
		}
	}
	return points;
}

void printall(database* points) {
	rdnode* temp;
	for (int count = 0; count < points->nodes.size(); count++) {
		temp = points->nodes[count];
		std::cout << temp->topic << std::endl;
	}
}

void rmknows(database* points) {
	rdnode* temp;
	for (int count = 0; count < points->nodes.size(); count++) {
		temp = points->nodes[count];
		temp->knows = false;
	}
}

void student(database* points) {
	std::cout << "Enter name of student file." << std::endl;
	std::vector<std::string> person;
	char filename[30];
	std::cin >> filename;
	std::ifstream inputconf(filename);
	std::string line;
	while (getline (inputconf, line)) {
		person.push_back(line);
	}
	inputconf.close();
	rdnode* tempnode;
	bool finishloop = false;
	for (int count = 0; count < person.size(); count++) {
		for (int counter = 0; counter < points->nodes.size() && finishloop == false; counter++) {
			tempnode = points->nodes[counter];
			if (tempnode->topic == person[count]) {
				tempnode->knows = true;
				finishloop = true;
			}
		}
		finishloop = false;
	}
}

std::vector<std::string> prerequisites(rdnode* node, database* points) {
	std::vector<std::string> needtoknow;
	rdnode* parent;
	for (int count = 0; count < node->parents.size(); count++) {
		parent = node->parents[count];
		if (parent->knows == false) {
			bool alreadythere = false;
			for (int counter = 0; counter < needtoknow.size(); counter++) {
				if (parent->topic == needtoknow[counter]) {
					alreadythere = true;
				}
			}
			if (alreadythere == false) {
				needtoknow.push_back(parent->topic);
			}
			std::vector<std::string> alsoneed = prerequisites(parent, points);
			alreadythere = false;
			for (int counter = 0; counter < alsoneed.size(); counter++) {
				for (int counting = 0; counting < needtoknow.size(); counting++) {
					if (needtoknow[counting] == alsoneed[counter]) {
						alreadythere = true;
					}
				}
				if (alreadythere == false) {
					needtoknow.push_back(alsoneed[counter]);
				}
				alreadythere = false;
			}
		}
	}
	return needtoknow;
}

int main() {
	database* points = new database;
	points = populate(points);
	bool keeplooping = true;
	std::cout << "Do you have a student file? (y/n)?" << std::endl;
	char answer;
	std::cin >> answer;
	if (answer == 'y') {
		knows(points, true);
	}
	else {
		std::cout << "else is working" << std::endl;
		knows(points, false);
	}
	while (keeplooping) {
		std::cout << "Your options: Change student (a), List all learnable topics for current student (b), Find out what you need to learn before you can learn a specified topic (c), Print all topics in the database (d), Remove current database and build a new database (e), Add a database's nodes to the current database (f), Exit program (g)" << std::endl;
		std::cin >> answer;
		if (answer == 'a') {
			rmknows(points);
			std::cout << "Do you have a student file? (y/n)?" << std::endl;
			char answer;
			std::cin >> answer;
			if (answer == 'y') {
				knows(points, true);
			}
			else {
				knows(points, false);
			}
		}
		if (answer == 'b') {
			learnable(points);
		}
		if (answer == 'c') {
			std::cout << "Type in the name of the topic. ";
			std::string topicname;
			//std::cout << "before" << std::endl;
			std::cin.ignore();
			std::getline (std::cin, topicname);
			//std::cout << "after" << std::endl;
			rdnode* node;
			bool assigned = false;
			std::vector<std::string> gottalearn;
			for (int count = 0; count < points->nodes.size() && assigned == false; count++) {
				node = points->nodes[count];
				if (node->topic == topicname) {
					std::cout << "That topic exists in the database." << std::endl;
					assigned = true;
				}
			}
			if (assigned == false) {
				std::cout << "That topic isn't in the database. You may have spelled or formatted it incorrectly; make sure all your letters are lowercase." << std::endl;
			}
			else {
				gottalearn = prerequisites(node, points);
				if (gottalearn.size() == 0) {
					std::cout << "You can learn that now!" << std::endl;
				}
				else {
					std::cout << "You need to learn ";
					for (int count = 0; count < gottalearn.size(); count++) {
						std::cout << gottalearn[count];
						if (count + 1 < gottalearn.size()) {
							std::cout << " and ";
						}
					}
					std::cout << " before you can learn " << topicname << "." << std::endl;
				}
			}
		}
		if (answer == 'd') {
			printall(points);
		}
		if (answer == 'e') {
			depopulate(points);
			database* points = populate(points);
		}
		if (answer == 'f') {
			points = populate(points);
		}
		if (answer == 'g') {
			keeplooping = false;
		}
	}
	depopulate(points);
	return 0;
}
<|endoftext|>