<commit_before>/*
 * Copyright (c) 2003-2010, <NAME>.  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.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 */

#include <system.hh>

#include "item.h"

namespace ledger {

bool item_t::use_effective_date = false;

bool item_t::has_tag(const string& tag) const
{
  DEBUG("item.meta", "Checking if item has tag: " << tag);
  if (! metadata) {
    DEBUG("item.meta", "Item has no metadata at all");
    return false;
  }
  string_map::const_iterator i = metadata->find(tag);
#if defined(DEBUG_ON)
  if (SHOW_DEBUG("item.meta")) {
    if (i == metadata->end())
      DEBUG("item.meta", "Item does not have this tag");
    else
      DEBUG("item.meta", "Item has the tag!");
  }
#endif
  return i != metadata->end();
}

bool item_t::has_tag(const mask_t& tag_mask,
                     const optional<mask_t>& value_mask) const
{
  if (metadata) {
    foreach (const string_map::value_type& data, *metadata) {
      if (tag_mask.match(data.first)) {
        if (! value_mask)
          return true;
        else if (data.second.first)
          return value_mask->match(data.second.first->to_string());
      }
    }
  }
  return false;
}

optional<value_t> item_t::get_tag(const string& tag) const
{
  DEBUG("item.meta", "Getting item tag: " << tag);
  if (metadata) {
    DEBUG("item.meta", "Item has metadata");
    string_map::const_iterator i = metadata->find(tag);
    if (i != metadata->end()) {
      DEBUG("item.meta", "Found the item!");
      return (*i).second.first;
    }
  }
  return none;
}

optional<value_t> item_t::get_tag(const mask_t& tag_mask,
                                  const optional<mask_t>& value_mask) const
{
  if (metadata) {
    foreach (const string_map::value_type& data, *metadata) {
      if (tag_mask.match(data.first) &&
          (! value_mask ||
           (data.second.first &&
            value_mask->match(data.second.first->to_string())))) {
        return data.second.first;
      }
    }
  }
  return none;
}

item_t::string_map::iterator
item_t::set_tag(const string&            tag,
                const optional<value_t>& value,
                const bool               overwrite_existing)
{
  assert(! tag.empty());

  if (! metadata)
    metadata = string_map();

  DEBUG("item.meta", "Setting tag '" << tag << "' to value '"
        << (value ? *value : string_value("<none>")) << "'");

  optional<value_t> data = value;
  if (data &&
      (data->is_null() ||
       (data->is_string() && data->as_string().empty())))
    data = none;

  string_map::iterator i = metadata->find(tag);
  if (i == metadata->end()) {
    std::pair<string_map::iterator, bool> result
      = metadata->insert(string_map::value_type(tag, tag_data_t(data, false)));
    assert(result.second);
    return result.first;
  } else {
    if (overwrite_existing)
      (*i).second = tag_data_t(data, false);
    return i;
  }
}

void item_t::parse_tags(const char * p,
                        scope_t&     scope,
                        bool         overwrite_existing)
{
  if (const char * b = std::strchr(p, '[')) {
    if (*(b + 1) != '\0' &&
        (std::isdigit(*(b + 1)) || *(b + 1) == '=')) {
      if (const char * e = std::strchr(p, ']')) {
        char buf[256];
        std::strncpy(buf, b + 1, e - b - 1);
        buf[e - b - 1] = '\0';

        if (char * p = std::strchr(buf, '=')) {
          *p++ = '\0';
          _date_eff = parse_date(p);
        }
        if (buf[0])
          _date = parse_date(buf);
      }
    }
  }

  if (! std::strchr(p, ':'))
    return;

  scoped_array<char> buf(new char[std::strlen(p) + 1]);

  std::strcpy(buf.get(), p);

  string tag;
  bool   by_value = false;<commit_msg>Only look for [date] outside of metadata entries<commit_after>/*
 * Copyright (c) 2003-2010, <NAME>.  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.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 */

#include <system.hh>

#include "item.h"

namespace ledger {

bool item_t::use_effective_date = false;

bool item_t::has_tag(const string& tag) const
{
  DEBUG("item.meta", "Checking if item has tag: " << tag);
  if (! metadata) {
    DEBUG("item.meta", "Item has no metadata at all");
    return false;
  }
  string_map::const_iterator i = metadata->find(tag);
#if defined(DEBUG_ON)
  if (SHOW_DEBUG("item.meta")) {
    if (i == metadata->end())
      DEBUG("item.meta", "Item does not have this tag");
    else
      DEBUG("item.meta", "Item has the tag!");
  }
#endif
  return i != metadata->end();
}

bool item_t::has_tag(const mask_t& tag_mask,
                     const optional<mask_t>& value_mask) const
{
  if (metadata) {
    foreach (const string_map::value_type& data, *metadata) {
      if (tag_mask.match(data.first)) {
        if (! value_mask)
          return true;
        else if (data.second.first)
          return value_mask->match(data.second.first->to_string());
      }
    }
  }
  return false;
}

optional<value_t> item_t::get_tag(const string& tag) const
{
  DEBUG("item.meta", "Getting item tag: " << tag);
  if (metadata) {
    DEBUG("item.meta", "Item has metadata");
    string_map::const_iterator i = metadata->find(tag);
    if (i != metadata->end()) {
      DEBUG("item.meta", "Found the item!");
      return (*i).second.first;
    }
  }
  return none;
}

optional<value_t> item_t::get_tag(const mask_t& tag_mask,
                                  const optional<mask_t>& value_mask) const
{
  if (metadata) {
    foreach (const string_map::value_type& data, *metadata) {
      if (tag_mask.match(data.first) &&
          (! value_mask ||
           (data.second.first &&
            value_mask->match(data.second.first->to_string())))) {
        return data.second.first;
      }
    }
  }
  return none;
}

item_t::string_map::iterator
item_t::set_tag(const string&            tag,
                const optional<value_t>& value,
                const bool               overwrite_existing)
{
  assert(! tag.empty());

  if (! metadata)
    metadata = string_map();

  DEBUG("item.meta", "Setting tag '" << tag << "' to value '"
        << (value ? *value : string_value("<none>")) << "'");

  optional<value_t> data = value;
  if (data &&
      (data->is_null() ||
       (data->is_string() && data->as_string().empty())))
    data = none;

  string_map::iterator i = metadata->find(tag);
  if (i == metadata->end()) {
    std::pair<string_map::iterator, bool> result
      = metadata->insert(string_map::value_type(tag, tag_data_t(data, false)));
    assert(result.second);
    return result.first;
  } else {
    if (overwrite_existing)
      (*i).second = tag_data_t(data, false);
    return i;
  }
}

void item_t::parse_tags(const char * p,
                        scope_t&     scope,
                        bool         overwrite_existing)
{
  if (! std::strchr(p, ':')) {
    if (const char * b = std::strchr(p, '[')) {
      if (*(b + 1) != '\0' &&
          (std::isdigit(*(b + 1)) || *(b + 1) == '=')) {
        if (const char * e = std::strchr(p, ']')) {
          char buf[256];
          std::strncpy(buf, b + 1, e - b - 1);
          buf[e - b - 1] = '\0';

          if (char * p = std::strchr(buf, '=')) {
            *p++ = '\0';
            _date_eff = parse_date(p);
          }
          if (buf[0])
            _date = parse_date(buf);
        }
      }
    }
    return;
  }

  scoped_array<char> buf(new char[std::strlen(p) + 1]);

  std::strcpy(buf.get(), p);

  string tag;
  bool   by_value = false;
{'fraction_non_alphanumeric': 0.1336432306798373, 'fraction_numerical': 0.004261088514429595, 'mean_word_length': 2.7952958471150313, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4062175', 'n_tokens_mistral': 3281, 'n_tokens_neox': 3118, 'n_words': 974}