<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#pragma once

#include <algorithm>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <sstream>
#include <tuple>
#include <type_traits>

#include "AbstractDomain.h"

namespace sparta {

/*
 * The reduced cartesian product of abstract domains D1 x ... x Dn consists of
 * tuples of abstract values (v1, ..., vn) that represent the intersection of
 * the denotations of v1, ..., vn. Hence, all tuples that have at least one _|_
 * component are equated to _|_ (this is similar to abstract environments).
 * However, the intersection of the denotations may be empty even though none of
 * the components is equal to _|_.
 *
 * The reduction operation of the reduced product (usually denoted by the
 * Greek letter sigma in the literature) is used to decide whether the
 * intersection of the denotations of the components is empty when no
 * component is _|_. This occurs when the component domains have overlapping
 * denotations and can refine each other. For example, one could implement
 * Granger's local iterations to propagate information across components. The
 * reduction operation is specific to the abstract domains used in the product
 * and should be implemented in the derived class as the `reduce_product()`
 * method.
 *
 * The interface uses the curiously recurring template pattern, thus allowing
 * the product domain to define additional operations. This comes handy when
 * each component domain defines a common operation that has to be lifted to the
 * product.
 *
 * Example usage:
 *
 *  class D0 final : public AbstractDomain<D0> {
 *   public:
 *    D0 operation1(...) { ... }
 *    void operation2(...) { ... }
 *    ...
 *  };
 *
 *  class D1 final : public AbstractDomain<D1> {
 *   public:
 *    D1 operation1(...) { ... }
 *    void operation2(...) { ... }
 *    ...
 *  };
 *
 *  class D0xD1 final : public ProductAbstractDomain<D0xD1, D0, D1> {
 *   public:
 *    D0xD1 operation1(...) { ... }
 *    void operation2(...) {
 *      D0& x = get<0>();
 *      D1& y = get<1>();
 *      x.operation2();
 *      y.operation2();
 *      ...
 *      // Explicitly call the reduction operation
 *      reduce();
 *    }
 *    // The reduce_product method implements the mechanics of the reduction
 *    // operation. It is required by the API, even though it does nothing. The
 *    // reduction operates by changing the contents of the given tuple.
 *    static void reduce_product(std::tuple<D0, D1>& product) { ... }
 *    static D0xD1 bottom() {
 *      D0xD1 x;
 *      x.set_to_bottom();
 *      return x;
 *    }
 *    static D0xD1 top() {
 *      D0xD1 x;
 *      x.set_to_top();
 *      return x;
 *    }
 *    ...
 *  };
 *
 */
template <typename Derived, typename... Domains>
class ReducedProductAbstractDomain : public AbstractDomain<Derived> {
 public:
  ~ReducedProductAbstractDomain() {
    // The destructor is the only method that is guaranteed to be created when a
    // class template is instantiated. This is a good place to perform all the
    // sanity checks on the template parameters.
    static_assert(
        sizeof...(Domains) >= 2,
        "ReducedProductAbstractDomain requires at least two parameters");
    static_assert(std::is_void<decltype(Derived::reduce_product(
                      std::declval<std::tuple<Domains...>&>()))>::value,
                  "Derived::reduce_product() does not exist");
  }

  /*
   * Defining a public variadic constructor will invariably lead to instances of
   * the "Most Vexing Parse". Passing a tuple of elements as a single argument
   * to the constructor circumvents the issue without sacrificing readability.
   */
  explicit ReducedProductAbstractDomain(std::tuple<Domains...> product)
      : m_product(product) {
    // Since one or more components can be _|_, we need to normalize the
    // representation.
    normalize();<commit_msg>Introducing a move in ReducedProductAbstractDomain<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#pragma once

#include <algorithm>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <sstream>
#include <tuple>
#include <type_traits>

#include "AbstractDomain.h"

namespace sparta {

/*
 * The reduced cartesian product of abstract domains D1 x ... x Dn consists of
 * tuples of abstract values (v1, ..., vn) that represent the intersection of
 * the denotations of v1, ..., vn. Hence, all tuples that have at least one _|_
 * component are equated to _|_ (this is similar to abstract environments).
 * However, the intersection of the denotations may be empty even though none of
 * the components is equal to _|_.
 *
 * The reduction operation of the reduced product (usually denoted by the
 * Greek letter sigma in the literature) is used to decide whether the
 * intersection of the denotations of the components is empty when no
 * component is _|_. This occurs when the component domains have overlapping
 * denotations and can refine each other. For example, one could implement
 * Granger's local iterations to propagate information across components. The
 * reduction operation is specific to the abstract domains used in the product
 * and should be implemented in the derived class as the `reduce_product()`
 * method.
 *
 * The interface uses the curiously recurring template pattern, thus allowing
 * the product domain to define additional operations. This comes handy when
 * each component domain defines a common operation that has to be lifted to the
 * product.
 *
 * Example usage:
 *
 *  class D0 final : public AbstractDomain<D0> {
 *   public:
 *    D0 operation1(...) { ... }
 *    void operation2(...) { ... }
 *    ...
 *  };
 *
 *  class D1 final : public AbstractDomain<D1> {
 *   public:
 *    D1 operation1(...) { ... }
 *    void operation2(...) { ... }
 *    ...
 *  };
 *
 *  class D0xD1 final : public ProductAbstractDomain<D0xD1, D0, D1> {
 *   public:
 *    D0xD1 operation1(...) { ... }
 *    void operation2(...) {
 *      D0& x = get<0>();
 *      D1& y = get<1>();
 *      x.operation2();
 *      y.operation2();
 *      ...
 *      // Explicitly call the reduction operation
 *      reduce();
 *    }
 *    // The reduce_product method implements the mechanics of the reduction
 *    // operation. It is required by the API, even though it does nothing. The
 *    // reduction operates by changing the contents of the given tuple.
 *    static void reduce_product(std::tuple<D0, D1>& product) { ... }
 *    static D0xD1 bottom() {
 *      D0xD1 x;
 *      x.set_to_bottom();
 *      return x;
 *    }
 *    static D0xD1 top() {
 *      D0xD1 x;
 *      x.set_to_top();
 *      return x;
 *    }
 *    ...
 *  };
 *
 */
template <typename Derived, typename... Domains>
class ReducedProductAbstractDomain : public AbstractDomain<Derived> {
 public:
  ~ReducedProductAbstractDomain() {
    // The destructor is the only method that is guaranteed to be created when a
    // class template is instantiated. This is a good place to perform all the
    // sanity checks on the template parameters.
    static_assert(
        sizeof...(Domains) >= 2,
        "ReducedProductAbstractDomain requires at least two parameters");
    static_assert(std::is_void<decltype(Derived::reduce_product(
                      std::declval<std::tuple<Domains...>&>()))>::value,
                  "Derived::reduce_product() does not exist");
  }

  /*
   * Defining a public variadic constructor will invariably lead to instances of
   * the "Most Vexing Parse". Passing a tuple of elements as a single argument
   * to the constructor circumvents the issue without sacrificing readability.
   */
  explicit ReducedProductAbstractDomain(std::tuple<Domains...> product)
      : m_product(std::move(product)) {
    // Since one or more components can be _|_, we need to normalize the
    // representation.
    normalize();
{'fraction_non_alphanumeric': 0.10446668293873566, 'fraction_numerical': 0.00976324139614352, 'mean_word_length': 2.9493975903614458, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 43, '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': '1552577', 'n_tokens_mistral': 2295, 'n_tokens_neox': 2236, 'n_words': 903}