<commit_before>/**
\file
\brief Main header file for dsb::util.
*/
#ifndef DSB_UTIL_HPP
#define DSB_UTIL_HPP

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include "dsb/config.h"
#include "boost/filesystem/path.hpp"
#include "boost/noncopyable.hpp"


namespace dsb
{

/// Misc. utilities (i.e., stuff that didn't really fit anywhere else).
namespace util
{


/// Encodes a 16-bit unsigned integer using little-endian byte order.
void EncodeUint16(uint16_t source, char target[2]);


/// Encodes a 32-bit unsigned integer using little-endian byte order.
void EncodeUint32(uint32_t source, char target[4]);


/// Decodes a 16-bit unsigned integer using little-endian byte order.
uint16_t DecodeUint16(const char source[2]);


/// Decodes a 32-bit unsigned integer using little-endian byte order.
uint32_t DecodeUint32(const char source[4]);


/// Returns a string that contains a random UUID.
std::string RandomUUID();


/**
\brief  Creates a random string.

This creates a string of the given size by randomly selecting characters from
`charSet`, which must be a null-terminated string.

\throws std::invalid_argument
    If `charSet` is null or empty.
*/
std::string RandomString(size_t size, const char* charSet);

/**
\brief  Returns the current UTC time in the ISO 8601 "basic" format.

This returns a string on the form `yyyymmddThhmmssZ` (where the lower-case
letters represent the date/time numbers).
*/
std::string Timestamp();


/**
\brief  Moves a value, replacing it with another one.

This function works just like `std::move`, except that it only works on lvalues
and assigns an explicit value to the variable which is being moved from.  This
is inefficient for types that provide move semantics (`std::move` should be used
for those), but useful for e.g. built-in types.
*/
template<typename T1, typename T2>
T1 MoveAndReplace(T1& variable, const T2& replacement)
{
    auto tmp = std::move(variable);
    variable = replacement;
    return std::move(tmp);
}

/**
\brief  Overload of MoveAndReplace() that replaces `variable` with a
        default-constructed value.
*/
template<typename T>
T MoveAndReplace(T& variable)
{
    return MoveAndReplace(variable, T());
}


/**
\brief  Calls the given function(-like object), but only after swapping it with
        a default-constructed one.

This is useful for function objects that may only be called once, such as
one-shot callbacks.

`LastCall(f, x)` is equivalent to the following:
~~~{.cpp}
F tmp;
swap(f, tmp);
tmp(x);
~~~
Thus, `f` will be left in its default-constructed state even if it throws.
(However, if the default constructor throws in the first line, `f` will
never be called at all.)
*/
template<typename F>
void LastCall(F& f)
{
    F tmp;
    swap(f, tmp);
    tmp();
}

template<typename F, typename A0>
void LastCall(F& f, A0&& a0)
{
    F tmp;
    swap(f, tmp);
    tmp(std::forward<A0>(a0));
}


template<typename Action>
class ScopeGuard : boost::noncopyable
{
public:
    explicit ScopeGuard(Action action) : m_active(true), m_action(action) { }

    ScopeGuard(ScopeGuard&& other)
        : m_active(MoveAndReplace(other.m_active, false)),
          m_action(std::move(other.m_action))
    { }

    ScopeGuard& operator=(ScopeGuard&& other)
    {
        m_active = MoveAndReplace(other.m_active, false);
        m_action = std::move(other.m_action);
    }

    ~ScopeGuard() { if (m_active) m_action(); }

private:
    bool m_active;
    Action m_action;
};

/**
\brief  Scope guard.<commit_msg>Allow any number of arguments in LastCall<commit_after>/**
\file
\brief Main header file for dsb::util.
*/
#ifndef DSB_UTIL_HPP
#define DSB_UTIL_HPP

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include "dsb/config.h"
#include "boost/filesystem/path.hpp"
#include "boost/noncopyable.hpp"


namespace dsb
{

/// Misc. utilities (i.e., stuff that didn't really fit anywhere else).
namespace util
{


/// Encodes a 16-bit unsigned integer using little-endian byte order.
void EncodeUint16(uint16_t source, char target[2]);


/// Encodes a 32-bit unsigned integer using little-endian byte order.
void EncodeUint32(uint32_t source, char target[4]);


/// Decodes a 16-bit unsigned integer using little-endian byte order.
uint16_t DecodeUint16(const char source[2]);


/// Decodes a 32-bit unsigned integer using little-endian byte order.
uint32_t DecodeUint32(const char source[4]);


/// Returns a string that contains a random UUID.
std::string RandomUUID();


/**
\brief  Creates a random string.

This creates a string of the given size by randomly selecting characters from
`charSet`, which must be a null-terminated string.

\throws std::invalid_argument
    If `charSet` is null or empty.
*/
std::string RandomString(size_t size, const char* charSet);

/**
\brief  Returns the current UTC time in the ISO 8601 "basic" format.

This returns a string on the form `yyyymmddThhmmssZ` (where the lower-case
letters represent the date/time numbers).
*/
std::string Timestamp();


/**
\brief  Moves a value, replacing it with another one.

This function works just like `std::move`, except that it only works on lvalues
and assigns an explicit value to the variable which is being moved from.  This
is inefficient for types that provide move semantics (`std::move` should be used
for those), but useful for e.g. built-in types.
*/
template<typename T1, typename T2>
T1 MoveAndReplace(T1& variable, const T2& replacement)
{
    auto tmp = std::move(variable);
    variable = replacement;
    return std::move(tmp);
}

/**
\brief  Overload of MoveAndReplace() that replaces `variable` with a
        default-constructed value.
*/
template<typename T>
T MoveAndReplace(T& variable)
{
    return MoveAndReplace(variable, T());
}


/**
\brief  Calls the given function(-like object), but only after swapping it with
        a default-constructed one.

This is useful for function objects that may only be called once, such as
one-shot callbacks.

`LastCall(f, x)` is equivalent to the following:
~~~{.cpp}
F tmp;
swap(f, tmp);
tmp(x);
~~~
Thus, `f` will be left in its default-constructed state even if it throws.
(However, if the default constructor throws in the first line, `f` will
never be called at all.)
*/
template<typename F>
void LastCall(F& f)
{
    F tmp;
    swap(f, tmp);
    tmp();
}

template<typename F, typename... Args>
void LastCall(F& f, Args&&... args)
{
    F tmp;
    swap(f, tmp);
    tmp(std::forward<Args>(args)...);
}


template<typename Action>
class ScopeGuard : boost::noncopyable
{
public:
    explicit ScopeGuard(Action action) : m_active(true), m_action(action) { }

    ScopeGuard(ScopeGuard&& other)
        : m_active(MoveAndReplace(other.m_active, false)),
          m_action(std::move(other.m_action))
    { }

    ScopeGuard& operator=(ScopeGuard&& other)
    {
        m_active = MoveAndReplace(other.m_active, false);
        m_action = std::move(other.m_action);
    }

    ~ScopeGuard() { if (m_active) m_action(); }

private:
    bool m_active;
    Action m_action;
};

/**
\brief  Scope guard.
{'fraction_non_alphanumeric': 0.11409585748621519, 'fraction_numerical': 0.011169235119468402, 'mean_word_length': 3.9056865464632455, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, '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': '7215298', 'n_tokens_mistral': 2316, 'n_tokens_neox': 2216, 'n_words': 803}