<commit_before>#ifndef FUTURE_H
#define FUTURE_H

#include <mutex>
#include <functional>
#include <memory>
#include <exception>
#include <vector>
#include <utility>
#include <condition_variable>

template <typename T>
class shared_state;
template <typename T>
class promise;
template <typename T>
class future;

class executor
{
public:
  virtual void queue(std::function<void()> func) = 0;
  template <typename T>
  auto async(T func) -> future<decltype(func())>;
};

executor *default_executor();

template <typename T>
auto async(T func) -> future<decltype(func())> {
  return default_executor()->async(func);
}

template <typename T>
class future {
public:
  T get() const;
  bool is_ready() const;
  template <typename U>
  auto then(U func, executor *exec = default_executor()) -> future<decltype(func(*(future<T>*)0))>;
//private:
  future(std::shared_ptr<shared_state<T>> state);
  friend class promise<T>;
  std::shared_ptr<shared_state<T>> state;
};

struct promise_exception : public std::exception {
};

template <typename T>
class shared_state {
public:
  shared_state()
  : storage(NULL)
  {
  }
  ~shared_state()
  {
    delete storage;
  }
  void set(T &&value) {
    std::unique_lock<std::mutex> lk(m);
    storage = new T(std::move(value));
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void set(const T &value) {
    std::unique_lock<std::mutex> lk(m);
    storage = new T(value);
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void set_error(std::exception_ptr eptr) {
    std::unique_lock<std::mutex> lk(m);
    this->eptr = eptr;
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  T get() {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [this]{ return value_set; });
    if (eptr)
      std::rethrow_exception(eptr);
    return *storage;
  }
  void then(std::function<void()> cb, executor *exec) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      exec->async(cb);
    else
      cbs.push_back(std::make_pair(exec, cb));
  }
  std::vector<std::pair<executor*, std::function<void()>>> cbs;
  T *storage;
  std::exception_ptr eptr;
  mutable std::mutex m;
  mutable std::condition_variable cv;
  bool value_set = false;
};

template <>
struct shared_state<void> {
public:
  void set() {
    std::unique_lock<std::mutex> lk(m);
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void set_error(std::exception_ptr eptr) {
    std::unique_lock<std::mutex> lk(m);
    this->eptr = eptr;
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void get() const {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [this]{ return value_set; });
    if (eptr)
      std::rethrow_exception(eptr);
  }
  void then(std::function<void()> cb, executor *exec) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      exec->async(cb);
    else
      cbs.push_back(std::make_pair(exec, cb));
  }<commit_msg>Only allow writing the promise once<commit_after>#ifndef FUTURE_H
#define FUTURE_H

#include <mutex>
#include <functional>
#include <memory>
#include <exception>
#include <vector>
#include <utility>
#include <condition_variable>

template <typename T>
class shared_state;
template <typename T>
class promise;
template <typename T>
class future;

class executor
{
public:
  virtual void queue(std::function<void()> func) = 0;
  template <typename T>
  auto async(T func) -> future<decltype(func())>;
};

executor *default_executor();

template <typename T>
auto async(T func) -> future<decltype(func())> {
  return default_executor()->async(func);
}

template <typename T>
class future {
public:
  T get() const;
  bool is_ready() const;
  template <typename U>
  auto then(U func, executor *exec = default_executor()) -> future<decltype(func(*(future<T>*)0))>;
//private:
  future(std::shared_ptr<shared_state<T>> state);
  friend class promise<T>;
  std::shared_ptr<shared_state<T>> state;
};

struct promise_exception : public std::exception {
};

struct promise_already_satisfied : promise_exception {};

template <typename T>
class shared_state {
public:
  shared_state()
  : storage(NULL)
  {
  }
  ~shared_state()
  {
    delete storage;
  }
  void set(T &&value) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      throw promise_already_satisfied();
    storage = new T(std::move(value));
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void set(const T &value) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      throw promise_already_satisfied();
    storage = new T(value);
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void set_error(std::exception_ptr eptr) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      throw promise_already_satisfied();
    this->eptr = eptr;
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  T get() {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [this]{ return value_set; });
    if (eptr)
      std::rethrow_exception(eptr);
    return *storage;
  }
  void then(std::function<void()> cb, executor *exec) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      exec->async(cb);
    else
      cbs.push_back(std::make_pair(exec, cb));
  }
  std::vector<std::pair<executor*, std::function<void()>>> cbs;
  T *storage;
  std::exception_ptr eptr;
  mutable std::mutex m;
  mutable std::condition_variable cv;
  bool value_set = false;
};

template <>
struct shared_state<void> {
public:
  void set() {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      throw promise_already_satisfied();
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void set_error(std::exception_ptr eptr) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      throw promise_already_satisfied();
    this->eptr = eptr;
    value_set = true;
    cv.notify_all();
    for (const auto &p : cbs)
      p.first->async(p.second);
    cbs.clear();
  }
  void get() const {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [this]{ return value_set; });
    if (eptr)
      std::rethrow_exception(eptr);
  }
  void then(std::function<void()> cb, executor *exec) {
    std::unique_lock<std::mutex> lk(m);
    if (value_set)
      exec->async(cb);
    else
      cbs.push_back(std::make_pair(exec, cb));
  }
{'fraction_non_alphanumeric': 0.16132322937918975, 'fraction_numerical': 0.0005829204313611193, 'mean_word_length': 3.713598901098901, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 111, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6048005', 'n_tokens_mistral': 2532, 'n_tokens_neox': 2508, 'n_words': 548}