<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/base/ParameterMap.h>
#include <shogun/base/Parameter.h>
#include <shogun/mathematics/Math.h>

using namespace shogun;

SGParamInfo::SGParamInfo()
{
	init();
}

SGParamInfo::SGParamInfo(const SGParamInfo& orig)
{
	init();

	/* copy name */
	m_name=strdup(orig.m_name);

	m_ctype=orig.m_ctype;
	m_stype=orig.m_stype;
	m_ptype=orig.m_ptype;
	m_param_version=orig.m_param_version;
}

SGParamInfo::SGParamInfo(const char* name, EContainerType ctype,
		EStructType stype, EPrimitiveType ptype, int32_t param_version)
{
	init();

	/* copy name */
	m_name=strdup(name);

	m_ctype=ctype;
	m_stype=stype;
	m_ptype=ptype;
	m_param_version=param_version;
}

SGParamInfo::SGParamInfo(const TParameter* param, int32_t param_version)
{
	init();

	/* copy name */
	m_name=strdup(param->m_name);

	TSGDataType type=param->m_datatype;
	m_ctype=type.m_ctype;
	m_stype=type.m_stype;
	m_ptype=type.m_ptype;
	m_param_version=param_version;
}

SGParamInfo::~SGParamInfo()
{
	SG_FREE(m_name);
}

char* SGParamInfo::to_string() const
{
	char* buffer=SG_MALLOC(char, 200);
	strcpy(buffer, "SGParamInfo with: ");
	strcat(buffer, "name=\"");
	strcat(buffer, m_name);
	strcat(buffer, "\", type=");

	TSGDataType t(m_ctype, m_stype, m_ptype);
	index_t l=100;
	char* b=SG_MALLOC(char, l);
	t.to_string(b, l);
	strcat(buffer, b);
	SG_FREE(b);

	b=SG_MALLOC(char, 10);
	sprintf(b, "%d", m_param_version);
	strcat(buffer, ", version=");
	strcat(buffer, b);
	SG_FREE(b);

	return buffer;
}

void SGParamInfo::print_param_info()
{
	char* s=to_string();
	SG_SPRINT("%s\n", s);
	SG_FREE(s);
}

SGParamInfo* SGParamInfo::duplicate() const
{
	return new SGParamInfo(m_name, m_ctype, m_stype, m_ptype, m_param_version);
}

void SGParamInfo::init()
{
	m_name=NULL;
	m_ctype=(EContainerType) -1;
	m_stype=(EStructType) -1;
	m_ptype=(EPrimitiveType) -1;
	m_param_version=-1;
}

bool SGParamInfo::operator==(const SGParamInfo& other) const
{
	bool result=true;
	result&=!strcmp(m_name, other.m_name);
	result&=m_ctype==other.m_ctype;
	result&=m_stype==other.m_stype;
	result&=m_ptype==other.m_ptype;
	result&=m_param_version==other.m_param_version;
	return result;
}

bool SGParamInfo::operator<(const SGParamInfo& other) const
{
	int32_t result=strcmp(m_name, other.m_name);

	if (result==0)
	{
		if (m_param_version==other.m_param_version)
		{
			if (m_ctype==other.m_ctype)
			{
				if (m_stype==other.m_stype)
				{
					if (m_ptype==other.m_ptype)
					{
						return false;
					}
					else
						return m_ptype<other.m_ptype;
				}
				else
					return m_stype<other.m_stype;
			}
			else
				return m_ctype<other.m_ctype;
		}
		else
			return m_param_version<other.m_param_version;

	}
	else
		return result<0;
}

bool SGParamInfo::operator>(const SGParamInfo& other) const
{
	int32_t result=strcmp(m_name, other.m_name);

		if (result==0)
		{
			if (m_param_version==other.m_param_version)
			{
				if (m_ctype==other.m_ctype)
				{
					if (m_stype==other.m_stype)
					{
						if (m_ptype==other.m_ptype)
						{
							return false;
						}
						else
							return m_ptype>other.m_ptype;
					}
					else
						return m_stype>other.m_stype;
				}
				else
					return m_ctype>other.m_ctype;
			}
			else
				return m_param_version>other.m_param_version;

		}
		else
			return result>0;
}

ParameterMapElement::ParameterMapElement()
{
	init();
}

ParameterMapElement::ParameterMapElement(SGParamInfo* key,
		SGParamInfo* value)
{
	init();

	m_key=key;
	m_value=value;
}

ParameterMapElement::~ParameterMapElement()
{
	delete m_key;
	delete m_value;
}

bool ParameterMapElement::operator==(const ParameterMapElement& other) const
{
	return *m_key==*other.m_key;
}

bool ParameterMapElement::operator<(const ParameterMapElement& other) const
{
	return *m_key<*other.m_key;
}

bool ParameterMapElement::operator>(const ParameterMapElement& other) const
{
	return *m_key>*other.m_key;
}

void ParameterMapElement::init()
{
	m_key=NULL;
	m_value=NULL;
}

ParameterMap::ParameterMap()
{
	init();
}

void ParameterMap::init()
{
	m_finalized=false;
}

ParameterMap::~ParameterMap()
{
	for (index_t i=0; i<m_map_elements.get_num_elements(); ++i)
		delete m_map_elements[i];
}

void ParameterMap::put(SGParamInfo* key, SGParamInfo* value)
{
//	if (key->m_ptype==PT_SGOBJECT || value->m_ptype==PT_SGOBJECT)
//	{
//		SG_SPRINT("Parameter maps for CSGObjects are not yet supported\n");
//		SG_SNOTIMPLEMENTED;
//	}

	/* assert that versions do differ exactly one */
	if(key->m_param_version-value->m_param_version!=1)
	{
		char* s=key->to_string();
		char* t=value->to_string();
		SG_SERROR("Versions of parameter mappings from \"%s\" to \"%s\" have to"
				" differ exactly one\n", s, t);
		SG_FREE(s);
		SG_FREE(t);
	}

	m_map_elements.append_element(new ParameterMapElement(key, value));
	m_finalized=false;
}

SGParamInfo* ParameterMap::get(SGParamInfo* key) const
{
	index_t num_elements=m_map_elements.get_num_elements();

	/* check if underlying array is sorted */
	if (!m_finalized && num_elements>1)
		SG_SERROR("Call finalize_map() before calling get()\n");

	/* do binary search in array of pointers */
	/* dummy element for searching */
	ParameterMapElement* dummy=new ParameterMapElement(key->duplicate(),
			key->duplicate());
	index_t index=CMath::binary_search<ParameterMapElement> (
			m_map_elements.get_array(), num_elements, dummy);
	delete dummy;

	if (index==-1)
		return NULL;

	ParameterMapElement* element=m_map_elements.get_element(index);
	SGParamInfo* value=element->m_value;

	return value;
}

void ParameterMap::finalize_map()
{
	/* sort underlying array */
	CMath::qsort<ParameterMapElement> (m_map_elements.get_array(),
			m_map_elements.get_num_elements());

	/* ensure that there are no duplicate keys */
	if (m_map_elements.get_num_elements()>1)
	{
		for (index_t i=1; i<m_map_elements.get_num_elements(); ++i)
		{
			SGParamInfo* key1=m_map_elements.get_element(i-1)->m_key;
			SGParamInfo* key2=m_map_elements.get_element(i)->m_key;
			if (*key1==*key2)
				SG_SERROR("ParameterMap::finalize_map(): duplicate key!\n");
		}
	}

	m_finalized=true;
}

void ParameterMap::print_map()
{
	for (index_t i=0; i< m_map_elements.get_num_elements(); ++i)
	{
		ParameterMapElement* current=m_map_elements[i];
		SG_SPRINT("%d\n", i);
		SG_SPRINT("key: ");
		current->m_key->print_param_info();
		SG_SPRINT("value: ");
		current->m_value->print_param_info();
	}
}
<commit_msg>white space changes<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/base/ParameterMap.h>
#include <shogun/base/Parameter.h>
#include <shogun/mathematics/Math.h>

using namespace shogun;

SGParamInfo::SGParamInfo()
{
	init();
}

SGParamInfo::SGParamInfo(const SGParamInfo& orig)
{
	init();

	/* copy name */
	m_name=strdup(orig.m_name);

	m_ctype=orig.m_ctype;
	m_stype=orig.m_stype;
	m_ptype=orig.m_ptype;
	m_param_version=orig.m_param_version;
}

SGParamInfo::SGParamInfo(const char* name, EContainerType ctype,
		EStructType stype, EPrimitiveType ptype, int32_t param_version)
{
	init();

	/* copy name */
	m_name=strdup(name);

	m_ctype=ctype;
	m_stype=stype;
	m_ptype=ptype;
	m_param_version=param_version;
}

SGParamInfo::SGParamInfo(const TParameter* param, int32_t param_version)
{
	init();

	/* copy name */
	m_name=strdup(param->m_name);

	TSGDataType type=param->m_datatype;
	m_ctype=type.m_ctype;
	m_stype=type.m_stype;
	m_ptype=type.m_ptype;
	m_param_version=param_version;
}

SGParamInfo::~SGParamInfo()
{
	SG_FREE(m_name);
}

char* SGParamInfo::to_string() const
{
	char* buffer=SG_MALLOC(char, 200);
	strcpy(buffer, "SGParamInfo with: ");
	strcat(buffer, "name=\"");
	strcat(buffer, m_name);
	strcat(buffer, "\", type=");

	TSGDataType t(m_ctype, m_stype, m_ptype);
	index_t l=100;
	char* b=SG_MALLOC(char, l);
	t.to_string(b, l);
	strcat(buffer, b);
	SG_FREE(b);

	b=SG_MALLOC(char, 10);
	sprintf(b, "%d", m_param_version);
	strcat(buffer, ", version=");
	strcat(buffer, b);
	SG_FREE(b);

	return buffer;
}

void SGParamInfo::print_param_info()
{
	char* s=to_string();
	SG_SPRINT("%s\n", s);
	SG_FREE(s);
}

SGParamInfo* SGParamInfo::duplicate() const
{
	return new SGParamInfo(m_name, m_ctype, m_stype, m_ptype, m_param_version);
}

void SGParamInfo::init()
{
	m_name=NULL;
	m_ctype=(EContainerType) -1;
	m_stype=(EStructType) -1;
	m_ptype=(EPrimitiveType) -1;
	m_param_version=-1;
}

bool SGParamInfo::operator==(const SGParamInfo& other) const
{
	bool result=true;
	result&=!strcmp(m_name, other.m_name);
	result&=m_ctype==other.m_ctype;
	result&=m_stype==other.m_stype;
	result&=m_ptype==other.m_ptype;
	result&=m_param_version==other.m_param_version;
	return result;
}

bool SGParamInfo::operator<(const SGParamInfo& other) const
{
	int32_t result=strcmp(m_name, other.m_name);

	if (result==0)
	{
		if (m_param_version==other.m_param_version)
		{
			if (m_ctype==other.m_ctype)
			{
				if (m_stype==other.m_stype)
				{
					if (m_ptype==other.m_ptype)
					{
						return false;
					}
					else
						return m_ptype<other.m_ptype;
				}
				else
					return m_stype<other.m_stype;
			}
			else
				return m_ctype<other.m_ctype;
		}
		else
			return m_param_version<other.m_param_version;

	}
	else
		return result<0;
}

bool SGParamInfo::operator>(const SGParamInfo& other) const
{
	int32_t result=strcmp(m_name, other.m_name);

	if (result==0)
	{
		if (m_param_version==other.m_param_version)
		{
			if (m_ctype==other.m_ctype)
			{
				if (m_stype==other.m_stype)
				{
					if (m_ptype==other.m_ptype)
					{
						return false;
					}
					else
						return m_ptype>other.m_ptype;
				}
				else
					return m_stype>other.m_stype;
			}
			else
				return m_ctype>other.m_ctype;
		}
		else
			return m_param_version>other.m_param_version;

	}
	else
		return result>0;
}

ParameterMapElement::ParameterMapElement()
{
	init();
}

ParameterMapElement::ParameterMapElement(SGParamInfo* key,
		SGParamInfo* value)
{
	init();

	m_key=key;
	m_value=value;
}

ParameterMapElement::~ParameterMapElement()
{
	delete m_key;
	delete m_value;
}

bool ParameterMapElement::operator==(const ParameterMapElement& other) const
{
	return *m_key==*other.m_key;
}

bool ParameterMapElement::operator<(const ParameterMapElement& other) const
{
	return *m_key<*other.m_key;
}

bool ParameterMapElement::operator>(const ParameterMapElement& other) const
{
	return *m_key>*other.m_key;
}

void ParameterMapElement::init()
{
	m_key=NULL;
	m_value=NULL;
}

ParameterMap::ParameterMap()
{
	init();
}

void ParameterMap::init()
{
	m_finalized=false;
}

ParameterMap::~ParameterMap()
{
	for (index_t i=0; i<m_map_elements.get_num_elements(); ++i)
		delete m_map_elements[i];
}

void ParameterMap::put(SGParamInfo* key, SGParamInfo* value)
{
//	if (key->m_ptype==PT_SGOBJECT || value->m_ptype==PT_SGOBJECT)
//	{
//		SG_SPRINT("Parameter maps for CSGObjects are not yet supported\n");
//		SG_SNOTIMPLEMENTED;
//	}

	/* assert that versions do differ exactly one */
	if(key->m_param_version-value->m_param_version!=1)
	{
		char* s=key->to_string();
		char* t=value->to_string();
		SG_SERROR("Versions of parameter mappings from \"%s\" to \"%s\" have to"
				" differ exactly one\n", s, t);
		SG_FREE(s);
		SG_FREE(t);
	}

	m_map_elements.append_element(new ParameterMapElement(key, value));
	m_finalized=false;
}

SGParamInfo* ParameterMap::get(SGParamInfo* key) const
{
	index_t num_elements=m_map_elements.get_num_elements();

	/* check if underlying array is sorted */
	if (!m_finalized && num_elements>1)
		SG_SERROR("Call finalize_map() before calling get()\n");

	/* do binary search in array of pointers */
	/* dummy element for searching */
	ParameterMapElement* dummy=new ParameterMapElement(key->duplicate(),
			key->duplicate());
	index_t index=CMath::binary_search<ParameterMapElement> (
			m_map_elements.get_array(), num_elements, dummy);
	delete dummy;

	if (index==-1)
		return NULL;

	ParameterMapElement* element=m_map_elements.get_element(index);
	SGParamInfo* value=element->m_value;

	return value;
}

void ParameterMap::finalize_map()
{
	/* sort underlying array */
	CMath::qsort<ParameterMapElement> (m_map_elements.get_array(),
			m_map_elements.get_num_elements());

	/* ensure that there are no duplicate keys */
	if (m_map_elements.get_num_elements()>1)
	{
		for (index_t i=1; i<m_map_elements.get_num_elements(); ++i)
		{
			SGParamInfo* key1=m_map_elements.get_element(i-1)->m_key;
			SGParamInfo* key2=m_map_elements.get_element(i)->m_key;
			if (*key1==*key2)
				SG_SERROR("ParameterMap::finalize_map(): duplicate key!\n");
		}
	}

	m_finalized=true;
}

void ParameterMap::print_map()
{
	for (index_t i=0; i< m_map_elements.get_num_elements(); ++i)
	{
		ParameterMapElement* current=m_map_elements[i];
		SG_SPRINT("%d\n", i);
		SG_SPRINT("key: ");
		current->m_key->print_param_info();
		SG_SPRINT("value: ");
		current->m_value->print_param_info();
	}
}
<|endoftext|>


<commit_before>/*
* X.509 SIGNED Object
* (C) 1999-2007 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/x509_obj.h>
#include <botan/pubkey.h>
#include <botan/oids.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/parsing.h>
#include <botan/pem.h>
#include <algorithm>

namespace Botan {

namespace {
struct Pss_params
   {
   AlgorithmIdentifier hash_algo;
   AlgorithmIdentifier mask_gen_algo;
   AlgorithmIdentifier mask_gen_hash;  // redundant: decoded mask_gen_algo.parameters
   size_t salt_len;
   size_t trailer_field;
   };

Pss_params decode_pss_params(const std::vector<uint8_t>& encoded_pss_params)
   {
   Pss_params pss_parameter;
   BER_Decoder(encoded_pss_params)
      .start_cons(SEQUENCE)
         .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, AlgorithmIdentifier("SHA-160",
                    AlgorithmIdentifier::USE_NULL_PARAM))
         .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE,
                    AlgorithmIdentifier("MGF1", DER_Encoder().encode(AlgorithmIdentifier("SHA-160",
                                        AlgorithmIdentifier::USE_NULL_PARAM)).get_contents_unlocked()))
         .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20))
         .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1))
      .end_cons();

   BER_Decoder(pss_parameter.mask_gen_algo.parameters).decode(pss_parameter.mask_gen_hash);

   return pss_parameter;
   }
}

/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(DataSource& stream, const std::string& labels)
   {
   init(stream, labels);
   }

#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(const std::string& file, const std::string& labels)
   {
   DataSource_Stream stream(file, true);
   init(stream, labels);
   }
#endif

/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(const std::vector<uint8_t>& vec, const std::string& labels)
   {
   DataSource_Memory stream(vec.data(), vec.size());
   init(stream, labels);
   }

/*
* Read a PEM or BER X.509 object
*/
void X509_Object::init(DataSource& in, const std::string& labels)
   {
   m_PEM_labels_allowed = split_on(labels, '/');
   if(m_PEM_labels_allowed.size() < 1)
      throw Invalid_Argument("Bad labels argument to X509_Object");

   m_PEM_label_pref = m_PEM_labels_allowed[0];
   std::sort(m_PEM_labels_allowed.begin(), m_PEM_labels_allowed.end());

   try {
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
         {
         BER_Decoder dec(in);
         decode_from(dec);
         }
      else
         {
         std::string got_label;
         DataSource_Memory ber(PEM_Code::decode(in, got_label));

         if(!std::binary_search(m_PEM_labels_allowed.begin(),
                                m_PEM_labels_allowed.end(), got_label))
            throw Decoding_Error("Invalid PEM label: " + got_label);

         BER_Decoder dec(ber);
         decode_from(dec);
         }
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed: " + e.what());
      }
   }

void X509_Object::encode_into(DER_Encoder& to) const
   {
   to.start_cons(SEQUENCE)
         .start_cons(SEQUENCE)
            .raw_bytes(signed_body())
         .end_cons()
         .encode(signature_algorithm())
         .encode(signature(), BIT_STRING)
      .end_cons();
   }

/*
* Read a BER encoded X.509 object
*/
void X509_Object::decode_from(BER_Decoder& from)
   {
   from.start_cons(SEQUENCE)
         .start_cons(SEQUENCE)
            .raw_bytes(m_tbs_bits)
         .end_cons()
         .decode(m_sig_algo)
         .decode(m_sig, BIT_STRING)
      .end_cons();
   }

/*
* Return a BER encoded X.509 object
*/
std::vector<uint8_t> X509_Object::BER_encode() const
   {
   DER_Encoder der;
   encode_into(der);
   return der.get_contents_unlocked();
   }

/*
* Return a PEM encoded X.509 object
*/
std::string X509_Object::PEM_encode() const
   {
   return PEM_Code::encode(BER_encode(), m_PEM_label_pref);
   }

/*
* Return the TBS data
*/
std::vector<uint8_t> X509_Object::tbs_data() const
   {
   return ASN1::put_in_sequence(m_tbs_bits);
   }

/*
* Return the hash used in generating the signature
*/
std::string X509_Object::hash_used_for_signature() const
   {
   const OID oid = m_sig_algo.oid;
   std::vector<std::string> sig_info = split_on(OIDS::lookup(oid), '/');

   if(sig_info.size() != 2)
      throw Internal_Error("Invalid name format found for " +
                           oid.as_string());

   if(sig_info[1] == "EMSA4")
      {
      return OIDS::lookup(decode_pss_params(signature_algorithm().parameters).hash_algo.oid);
      }
   else
      {
      std::vector<std::string> pad_and_hash =
         parse_algorithm_name(sig_info[1]);

      if(pad_and_hash.size() != 2)
         {
         throw Internal_Error("Invalid name format " + sig_info[1]);
         }

      return pad_and_hash[1];
      }
   }

/*
* Check the signature on an object
*/
bool X509_Object::check_signature(const Public_Key* pub_key) const
   {
   if(!pub_key)
      throw Exception("No key provided for " + m_PEM_label_pref + " signature check");
   std::unique_ptr<const Public_Key> key(pub_key);
   return check_signature(*key);
   }

/*
* Check the signature on an object
*/
bool X509_Object::check_signature(const Public_Key& pub_key) const
   {
   try {
      std::vector<std::string> sig_info =
         split_on(OIDS::lookup(m_sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
         return false;

      std::string padding = sig_info[1];
      Signature_Format format =
         (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      if(padding == "EMSA4")
         {
         // "MUST contain RSASSA-PSS-params"
         if(signature_algorithm().parameters.empty())
            {
            return false;
            }

         Pss_params pss_parameter = decode_pss_params(signature_algorithm().parameters);

         // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
         std::string hash_algo = OIDS::lookup(pss_parameter.hash_algo.oid);
         if(hash_algo != "SHA-160" && hash_algo != "SHA-224" && hash_algo != "SHA-256" && hash_algo != "SHA-384"
               && hash_algo != "SHA-512")
            {
            return false;
            }

         std::string mgf_algo = OIDS::lookup(pss_parameter.mask_gen_algo.oid);
         if(mgf_algo != "MGF1")
            {
            return false;
            }

         // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm
         // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
         if(pss_parameter.mask_gen_hash.oid != pss_parameter.hash_algo.oid)
            {
            return false;
            }

         if(pss_parameter.trailer_field != 1)
            {
            return false;
            }

         padding += "(" + hash_algo;
         padding += "," + mgf_algo;
         padding += "," + std::to_string(pss_parameter.salt_len) +
                    ")";   // salt_len is actually not used for verification. Length is inferred from the signature
         }

      PK_Verifier verifier(pub_key, padding, format);

      return verifier.verify_message(tbs_data(), signature());
      }
   catch(std::exception&)
      {
      return false;
      }
   }

/*
* Apply the X.509 SIGNED macro
*/
std::vector<uint8_t> X509_Object::make_signed(PK_Signer* signer,
                                            RandomNumberGenerator& rng,
                                            const AlgorithmIdentifier& algo,
                                            const secure_vector<uint8_t>& tbs_bits)
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .raw_bytes(tbs_bits)
         .encode(algo)
         .encode(signer->sign_message(tbs_bits, rng), BIT_STRING)
      .end_cons()
   .get_contents_unlocked();
   }

/*
* Try to decode the actual information
*/
void X509_Object::do_decode()
   {
   try {
      force_decode();
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed (" +
                           e.what() + ")");
      }
   catch(Invalid_Argument& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed (" +
                           e.what() + ")");
      }
   }

}
<commit_msg>Use new Decoding_Error constructor<commit_after>/*
* X.509 SIGNED Object
* (C) 1999-2007 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/x509_obj.h>
#include <botan/pubkey.h>
#include <botan/oids.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/parsing.h>
#include <botan/pem.h>
#include <algorithm>

namespace Botan {

namespace {
struct Pss_params
   {
   AlgorithmIdentifier hash_algo;
   AlgorithmIdentifier mask_gen_algo;
   AlgorithmIdentifier mask_gen_hash;  // redundant: decoded mask_gen_algo.parameters
   size_t salt_len;
   size_t trailer_field;
   };

Pss_params decode_pss_params(const std::vector<uint8_t>& encoded_pss_params)
   {
   Pss_params pss_parameter;
   BER_Decoder(encoded_pss_params)
      .start_cons(SEQUENCE)
         .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, AlgorithmIdentifier("SHA-160",
                    AlgorithmIdentifier::USE_NULL_PARAM))
         .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE,
                    AlgorithmIdentifier("MGF1", DER_Encoder().encode(AlgorithmIdentifier("SHA-160",
                                        AlgorithmIdentifier::USE_NULL_PARAM)).get_contents_unlocked()))
         .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20))
         .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1))
      .end_cons();

   BER_Decoder(pss_parameter.mask_gen_algo.parameters).decode(pss_parameter.mask_gen_hash);

   return pss_parameter;
   }
}

/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(DataSource& stream, const std::string& labels)
   {
   init(stream, labels);
   }

#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(const std::string& file, const std::string& labels)
   {
   DataSource_Stream stream(file, true);
   init(stream, labels);
   }
#endif

/*
* Create a generic X.509 object
*/
X509_Object::X509_Object(const std::vector<uint8_t>& vec, const std::string& labels)
   {
   DataSource_Memory stream(vec.data(), vec.size());
   init(stream, labels);
   }

/*
* Read a PEM or BER X.509 object
*/
void X509_Object::init(DataSource& in, const std::string& labels)
   {
   m_PEM_labels_allowed = split_on(labels, '/');
   if(m_PEM_labels_allowed.size() < 1)
      throw Invalid_Argument("Bad labels argument to X509_Object");

   m_PEM_label_pref = m_PEM_labels_allowed[0];
   std::sort(m_PEM_labels_allowed.begin(), m_PEM_labels_allowed.end());

   try {
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
         {
         BER_Decoder dec(in);
         decode_from(dec);
         }
      else
         {
         std::string got_label;
         DataSource_Memory ber(PEM_Code::decode(in, got_label));

         if(!std::binary_search(m_PEM_labels_allowed.begin(),
                                m_PEM_labels_allowed.end(), got_label))
            throw Decoding_Error("Invalid PEM label: " + got_label);

         BER_Decoder dec(ber);
         decode_from(dec);
         }
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed: " + e.what());
      }
   }

void X509_Object::encode_into(DER_Encoder& to) const
   {
   to.start_cons(SEQUENCE)
         .start_cons(SEQUENCE)
            .raw_bytes(signed_body())
         .end_cons()
         .encode(signature_algorithm())
         .encode(signature(), BIT_STRING)
      .end_cons();
   }

/*
* Read a BER encoded X.509 object
*/
void X509_Object::decode_from(BER_Decoder& from)
   {
   from.start_cons(SEQUENCE)
         .start_cons(SEQUENCE)
            .raw_bytes(m_tbs_bits)
         .end_cons()
         .decode(m_sig_algo)
         .decode(m_sig, BIT_STRING)
      .end_cons();
   }

/*
* Return a BER encoded X.509 object
*/
std::vector<uint8_t> X509_Object::BER_encode() const
   {
   DER_Encoder der;
   encode_into(der);
   return der.get_contents_unlocked();
   }

/*
* Return a PEM encoded X.509 object
*/
std::string X509_Object::PEM_encode() const
   {
   return PEM_Code::encode(BER_encode(), m_PEM_label_pref);
   }

/*
* Return the TBS data
*/
std::vector<uint8_t> X509_Object::tbs_data() const
   {
   return ASN1::put_in_sequence(m_tbs_bits);
   }

/*
* Return the hash used in generating the signature
*/
std::string X509_Object::hash_used_for_signature() const
   {
   const OID oid = m_sig_algo.oid;
   std::vector<std::string> sig_info = split_on(OIDS::lookup(oid), '/');

   if(sig_info.size() != 2)
      throw Internal_Error("Invalid name format found for " +
                           oid.as_string());

   if(sig_info[1] == "EMSA4")
      {
      return OIDS::lookup(decode_pss_params(signature_algorithm().parameters).hash_algo.oid);
      }
   else
      {
      std::vector<std::string> pad_and_hash =
         parse_algorithm_name(sig_info[1]);

      if(pad_and_hash.size() != 2)
         {
         throw Internal_Error("Invalid name format " + sig_info[1]);
         }

      return pad_and_hash[1];
      }
   }

/*
* Check the signature on an object
*/
bool X509_Object::check_signature(const Public_Key* pub_key) const
   {
   if(!pub_key)
      throw Exception("No key provided for " + m_PEM_label_pref + " signature check");
   std::unique_ptr<const Public_Key> key(pub_key);
   return check_signature(*key);
   }

/*
* Check the signature on an object
*/
bool X509_Object::check_signature(const Public_Key& pub_key) const
   {
   try {
      std::vector<std::string> sig_info =
         split_on(OIDS::lookup(m_sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
         return false;

      std::string padding = sig_info[1];
      Signature_Format format =
         (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      if(padding == "EMSA4")
         {
         // "MUST contain RSASSA-PSS-params"
         if(signature_algorithm().parameters.empty())
            {
            return false;
            }

         Pss_params pss_parameter = decode_pss_params(signature_algorithm().parameters);

         // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
         std::string hash_algo = OIDS::lookup(pss_parameter.hash_algo.oid);
         if(hash_algo != "SHA-160" && hash_algo != "SHA-224" && hash_algo != "SHA-256" && hash_algo != "SHA-384"
               && hash_algo != "SHA-512")
            {
            return false;
            }

         std::string mgf_algo = OIDS::lookup(pss_parameter.mask_gen_algo.oid);
         if(mgf_algo != "MGF1")
            {
            return false;
            }

         // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm
         // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
         if(pss_parameter.mask_gen_hash.oid != pss_parameter.hash_algo.oid)
            {
            return false;
            }

         if(pss_parameter.trailer_field != 1)
            {
            return false;
            }

         padding += "(" + hash_algo;
         padding += "," + mgf_algo;
         padding += "," + std::to_string(pss_parameter.salt_len) +
                    ")";   // salt_len is actually not used for verification. Length is inferred from the signature
         }

      PK_Verifier verifier(pub_key, padding, format);

      return verifier.verify_message(tbs_data(), signature());
      }
   catch(std::exception&)
      {
      return false;
      }
   }

/*
* Apply the X.509 SIGNED macro
*/
std::vector<uint8_t> X509_Object::make_signed(PK_Signer* signer,
                                            RandomNumberGenerator& rng,
                                            const AlgorithmIdentifier& algo,
                                            const secure_vector<uint8_t>& tbs_bits)
   {
   return DER_Encoder()
      .start_cons(SEQUENCE)
         .raw_bytes(tbs_bits)
         .encode(algo)
         .encode(signer->sign_message(tbs_bits, rng), BIT_STRING)
      .end_cons()
   .get_contents_unlocked();
   }

/*
* Try to decode the actual information
*/
void X509_Object::do_decode()
   {
   try {
      force_decode();
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed", e.what());
      }
   catch(Invalid_Argument& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed", e.what());
      }
   }

}
<|endoftext|>


<commit_before>#include "Board.h"

Board::Board() {
	m_Board.reserve(9);
    m_Board.assign(9,PlayerOptions::EMPTY);
}

std::vector<PlayerOptions>& Board::getBoard() {
    return m_Board;
}

bool Board::isValidMove(int move) const {

    if(m_Board[move] == PlayerOptions::EMPTY) {
        return true;
    }

    return false;
}

bool Board::makeMove(GenericPlayer & player, int move)  {
	if(isValidMove(move)) {
		m_Board[move] = player.getCallSign();
		return true;
	}

	return false;
}

GameResults Board::Winner() {
	// Michael Dawson : Begining C++ Through Game Programming
    const int WINNING_ROWS[8][3] = {{0,1,2},
                                    {3,4,5},
                                    {6,7,8},
                                    {0,3,6},
                                    {1,4,7},
                                    {2,5,8},
                                    {0,4,8},
                                    {2,4,6}};

	for(int row=0; row < 8 ; row++) {
		if ((m_Board[WINNING_ROWS[row][0]] == m_Board[WINNING_ROWS[row][1]]) &&
			(m_Board[WINNING_ROWS[row][1]] == m_Board[WINNING_ROWS[row][2]])) {

			if(m_Board[WINNING_ROWS[row][0]] == PlayerOptions::X)
				return GameResults::X_WINS;

			if(m_Board[WINNING_ROWS[row][0]] == PlayerOptions::O)
				return GameResults::O_WINS;

		}
	}

	if(std::count(m_Board.begin(),m_Board.end(),PlayerOptions::EMPTY) == 0) {
		return GameResults::TIE;
	}

	return GameResults::NO_ONE_IS_WINNING_YET;

}
<commit_msg>alignment<commit_after>#include "Board.h"

Board::Board() {
	m_Board.reserve(9);
    m_Board.assign(9,PlayerOptions::EMPTY);
}

std::vector<PlayerOptions>& Board::getBoard() {
    return m_Board;
}

bool Board::isValidMove(int move) const {

    if(m_Board[move] == PlayerOptions::EMPTY) {
        return true;
    }

    return false;
}

bool Board::makeMove(GenericPlayer & player, int move)  {
	if(isValidMove(move)) {
		m_Board[move] = player.getCallSign();
		return true;
	}

	return false;
}

GameResults Board::Winner() {
	// Michael Dawson : Begining C++ Through Game Programming
    const int WINNING_ROWS[8][3] = {{0,1,2},
                                    {3,4,5},
                                    {6,7,8},
                                    {0,3,6},
                                    {1,4,7},
                                    {2,5,8},
                                    {0,4,8},
                                    {2,4,6}};

    for(int row=0; row < 8 ; row++) {
        if ((m_Board[WINNING_ROWS[row][0]] == m_Board[WINNING_ROWS[row][1]]) &&
            (m_Board[WINNING_ROWS[row][1]] == m_Board[WINNING_ROWS[row][2]])) {

            if(m_Board[WINNING_ROWS[row][0]] == PlayerOptions::X)
                return GameResults::X_WINS;

            if(m_Board[WINNING_ROWS[row][0]] == PlayerOptions::O)
                return GameResults::O_WINS;

        }
    }

    if(std::count(m_Board.begin(),m_Board.end(),PlayerOptions::EMPTY) == 0) {
        return GameResults::TIE;
    }

    return GameResults::NO_ONE_IS_WINNING_YET;

}
<|endoftext|>


<commit_before>#include "cpuid.h"
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"

#include <atomic>
#include <cstdint>
#include <errno.h>
#include <fcntl.h>
#include <iterator>
#include <limits>
#include <tuple>
#include <unistd.h>

namespace __xray {

static std::pair<ssize_t, bool>
retryingReadSome(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT {
  auto BytesToRead = std::distance(Begin, End);
  ssize_t BytesRead;
  ssize_t TotalBytesRead = 0;
  while (BytesToRead && (BytesRead = read(Fd, Begin, BytesToRead))) {
    if (BytesRead == -1) {
      if (errno == EINTR)
        continue;
      Report("Read error; errno = %d\n", errno);
      return std::make_pair(TotalBytesRead, false);
    }

    TotalBytesRead += BytesRead;
    BytesToRead -= BytesRead;
    Begin += BytesRead;
  }
  return std::make_pair(TotalBytesRead, true);
}

static bool readValueFromFile(const char *Filename,
                              long long *Value) XRAY_NEVER_INSTRUMENT {
  int Fd = open(Filename, O_RDONLY | O_CLOEXEC);
  if (Fd == -1)
    return false;
  static constexpr size_t BufSize = 256;
  char Line[BufSize] = {};
  ssize_t BytesRead;
  bool Success;
  std::tie(BytesRead, Success) = retryingReadSome(Fd, Line, Line + BufSize);
  if (!Success)
    return false;
  close(Fd);
  char *End = nullptr;
  long long Tmp = internal_simple_strtoll(Line, &End, 10);
  bool Result = false;
  if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) {
    *Value = Tmp;
    Result = true;
  }
  return Result;
}

uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
  long long TSCFrequency = -1;
  if (readValueFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz",
                        &TSCFrequency)) {
    TSCFrequency *= 1000;
  } else if (readValueFromFile(
                 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
                 &TSCFrequency)) {
    TSCFrequency *= 1000;
  } else {
    Report("Unable to determine CPU frequency for TSC accounting.\n");
  }
  return TSCFrequency == -1 ? 0 : static_cast<uint64_t>(TSCFrequency);
}

static constexpr uint8_t CallOpCode = 0xe8;
static constexpr uint16_t MovR10Seq = 0xba41;
static constexpr uint16_t Jmp9Seq = 0x09eb;
static constexpr uint8_t JmpOpCode = 0xe9;
static constexpr uint8_t RetOpCode = 0xc3;

static constexpr int64_t MinOffset{std::numeric_limits<int32_t>::min()};
static constexpr int64_t MaxOffset{std::numeric_limits<int32_t>::max()};

bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
                        const XRaySledEntry &Sled,
                        void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
  // Here we do the dance of replacing the following sled:
  //
  // xray_sled_n:
  //   jmp +9
  //   <9 byte nop>
  //
  // With the following:
  //
  //   mov r10d, <function id>
  //   call <relative 32bit offset to entry trampoline>
  //
  // We need to do this in the following order:
  //
  // 1. Put the function id first, 2 bytes from the start of the sled (just
  // after the 2-byte jmp instruction).
  // 2. Put the call opcode 6 bytes from the start of the sled.
  // 3. Put the relative offset 7 bytes from the start of the sled.
  // 4. Do an atomic write over the jmp instruction for the "mov r10d"
  // opcode and first operand.
  //
  // Prerequisite is to compute the relative offset to the trampoline's address.
  int64_t TrampolineOffset = reinterpret_cast<int64_t>(Trampoline) -
                             (static_cast<int64_t>(Sled.Address) + 11);
  if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
    Report("XRay Entry trampoline (%p) too far from sled (%p)\n",
           Trampoline, reinterpret_cast<void *>(Sled.Address));
    return false;
  }
  if (Enable) {
    *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
    *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
    *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
        std::memory_order_release);
  } else {
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
        std::memory_order_release);
    // FIXME: Write out the nops still?
  }
  return true;
}

bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
                       const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
  // Here we do the dance of replacing the following sled:
  //
  // xray_sled_n:
  //   ret
  //   <10 byte nop>
  //
  // With the following:
  //
  //   mov r10d, <function id>
  //   jmp <relative 32bit offset to exit trampoline>
  //
  // 1. Put the function id first, 2 bytes from the start of the sled (just
  // after the 1-byte ret instruction).
  // 2. Put the jmp opcode 6 bytes from the start of the sled.
  // 3. Put the relative offset 7 bytes from the start of the sled.
  // 4. Do an atomic write over the jmp instruction for the "mov r10d"
  // opcode and first operand.
  //
  // Prerequisite is to compute the relative offset fo the
  // __xray_FunctionExit function's address.
  int64_t TrampolineOffset = reinterpret_cast<int64_t>(__xray_FunctionExit) -
                             (static_cast<int64_t>(Sled.Address) + 11);
  if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
    Report("XRay Exit trampoline (%p) too far from sled (%p)\n",
           __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address));
    return false;
  }
  if (Enable) {
    *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
    *reinterpret_cast<uint8_t *>(Sled.Address + 6) = JmpOpCode;
    *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
        std::memory_order_release);
  } else {
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint8_t> *>(Sled.Address), RetOpCode,
        std::memory_order_release);
    // FIXME: Write out the nops still?
  }
  return true;
}

bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
                           const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
  // Here we do the dance of replacing the tail call sled with a similar
  // sequence as the entry sled, but calls the tail exit sled instead.
  int64_t TrampolineOffset =
      reinterpret_cast<int64_t>(__xray_FunctionTailExit) -
      (static_cast<int64_t>(Sled.Address) + 11);
  if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
    Report("XRay Exit trampoline (%p) too far from sled (%p)\n",
           __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address));
    return false;
  }
  if (Enable) {
    *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
    *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
    *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
        std::memory_order_release);
  } else {
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
        std::memory_order_release);
    // FIXME: Write out the nops still?
  }
  return true;
}

// We determine whether the CPU we're running on has the correct features we
// need. In x86_64 this will be rdtscp support.
bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {
  unsigned int EAX, EBX, ECX, EDX;

  // We check whether rdtscp support is enabled. According to the x86_64 manual,
  // level should be set at 0x80000001, and we should have a look at bit 27 in
  // EDX. That's 0x8000000 (or 1u << 26).
  __get_cpuid(0x80000001, &EAX, &EBX, &ECX, &EDX);
  if (!(EDX & (1u << 26))) {
    Report("Missing rdtscp support.\n");
    return false;
  }
  return true;
}

} // namespace __xray
<commit_msg>[XRay] [compiler-rt] Plug a file descriptor leak in a failure case.<commit_after>#include "cpuid.h"
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"

#include <atomic>
#include <cstdint>
#include <errno.h>
#include <fcntl.h>
#include <iterator>
#include <limits>
#include <tuple>
#include <unistd.h>

namespace __xray {

static std::pair<ssize_t, bool>
retryingReadSome(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT {
  auto BytesToRead = std::distance(Begin, End);
  ssize_t BytesRead;
  ssize_t TotalBytesRead = 0;
  while (BytesToRead && (BytesRead = read(Fd, Begin, BytesToRead))) {
    if (BytesRead == -1) {
      if (errno == EINTR)
        continue;
      Report("Read error; errno = %d\n", errno);
      return std::make_pair(TotalBytesRead, false);
    }

    TotalBytesRead += BytesRead;
    BytesToRead -= BytesRead;
    Begin += BytesRead;
  }
  return std::make_pair(TotalBytesRead, true);
}

static bool readValueFromFile(const char *Filename,
                              long long *Value) XRAY_NEVER_INSTRUMENT {
  int Fd = open(Filename, O_RDONLY | O_CLOEXEC);
  if (Fd == -1)
    return false;
  static constexpr size_t BufSize = 256;
  char Line[BufSize] = {};
  ssize_t BytesRead;
  bool Success;
  std::tie(BytesRead, Success) = retryingReadSome(Fd, Line, Line + BufSize);
  close(Fd);
  if (!Success)
    return false;
  char *End = nullptr;
  long long Tmp = internal_simple_strtoll(Line, &End, 10);
  bool Result = false;
  if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) {
    *Value = Tmp;
    Result = true;
  }
  return Result;
}

uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
  long long TSCFrequency = -1;
  if (readValueFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz",
                        &TSCFrequency)) {
    TSCFrequency *= 1000;
  } else if (readValueFromFile(
                 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
                 &TSCFrequency)) {
    TSCFrequency *= 1000;
  } else {
    Report("Unable to determine CPU frequency for TSC accounting.\n");
  }
  return TSCFrequency == -1 ? 0 : static_cast<uint64_t>(TSCFrequency);
}

static constexpr uint8_t CallOpCode = 0xe8;
static constexpr uint16_t MovR10Seq = 0xba41;
static constexpr uint16_t Jmp9Seq = 0x09eb;
static constexpr uint8_t JmpOpCode = 0xe9;
static constexpr uint8_t RetOpCode = 0xc3;

static constexpr int64_t MinOffset{std::numeric_limits<int32_t>::min()};
static constexpr int64_t MaxOffset{std::numeric_limits<int32_t>::max()};

bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
                        const XRaySledEntry &Sled,
                        void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
  // Here we do the dance of replacing the following sled:
  //
  // xray_sled_n:
  //   jmp +9
  //   <9 byte nop>
  //
  // With the following:
  //
  //   mov r10d, <function id>
  //   call <relative 32bit offset to entry trampoline>
  //
  // We need to do this in the following order:
  //
  // 1. Put the function id first, 2 bytes from the start of the sled (just
  // after the 2-byte jmp instruction).
  // 2. Put the call opcode 6 bytes from the start of the sled.
  // 3. Put the relative offset 7 bytes from the start of the sled.
  // 4. Do an atomic write over the jmp instruction for the "mov r10d"
  // opcode and first operand.
  //
  // Prerequisite is to compute the relative offset to the trampoline's address.
  int64_t TrampolineOffset = reinterpret_cast<int64_t>(Trampoline) -
                             (static_cast<int64_t>(Sled.Address) + 11);
  if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
    Report("XRay Entry trampoline (%p) too far from sled (%p)\n",
           Trampoline, reinterpret_cast<void *>(Sled.Address));
    return false;
  }
  if (Enable) {
    *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
    *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
    *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
        std::memory_order_release);
  } else {
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
        std::memory_order_release);
    // FIXME: Write out the nops still?
  }
  return true;
}

bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
                       const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
  // Here we do the dance of replacing the following sled:
  //
  // xray_sled_n:
  //   ret
  //   <10 byte nop>
  //
  // With the following:
  //
  //   mov r10d, <function id>
  //   jmp <relative 32bit offset to exit trampoline>
  //
  // 1. Put the function id first, 2 bytes from the start of the sled (just
  // after the 1-byte ret instruction).
  // 2. Put the jmp opcode 6 bytes from the start of the sled.
  // 3. Put the relative offset 7 bytes from the start of the sled.
  // 4. Do an atomic write over the jmp instruction for the "mov r10d"
  // opcode and first operand.
  //
  // Prerequisite is to compute the relative offset fo the
  // __xray_FunctionExit function's address.
  int64_t TrampolineOffset = reinterpret_cast<int64_t>(__xray_FunctionExit) -
                             (static_cast<int64_t>(Sled.Address) + 11);
  if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
    Report("XRay Exit trampoline (%p) too far from sled (%p)\n",
           __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address));
    return false;
  }
  if (Enable) {
    *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
    *reinterpret_cast<uint8_t *>(Sled.Address + 6) = JmpOpCode;
    *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
        std::memory_order_release);
  } else {
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint8_t> *>(Sled.Address), RetOpCode,
        std::memory_order_release);
    // FIXME: Write out the nops still?
  }
  return true;
}

bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
                           const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
  // Here we do the dance of replacing the tail call sled with a similar
  // sequence as the entry sled, but calls the tail exit sled instead.
  int64_t TrampolineOffset =
      reinterpret_cast<int64_t>(__xray_FunctionTailExit) -
      (static_cast<int64_t>(Sled.Address) + 11);
  if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
    Report("XRay Exit trampoline (%p) too far from sled (%p)\n",
           __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address));
    return false;
  }
  if (Enable) {
    *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
    *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
    *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
        std::memory_order_release);
  } else {
    std::atomic_store_explicit(
        reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
        std::memory_order_release);
    // FIXME: Write out the nops still?
  }
  return true;
}

// We determine whether the CPU we're running on has the correct features we
// need. In x86_64 this will be rdtscp support.
bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {
  unsigned int EAX, EBX, ECX, EDX;

  // We check whether rdtscp support is enabled. According to the x86_64 manual,
  // level should be set at 0x80000001, and we should have a look at bit 27 in
  // EDX. That's 0x8000000 (or 1u << 26).
  __get_cpuid(0x80000001, &EAX, &EBX, &ECX, &EDX);
  if (!(EDX & (1u << 26))) {
    Report("Missing rdtscp support.\n");
    return false;
  }
  return true;
}

} // namespace __xray
<|endoftext|>


<commit_before>/*
 *  ti-pga2310
 *  github.com/kashev/ti-pga2310
 *
 *      An Arduino / Energia Library for control of a Texas Instruments
 *      PGA2310 Stereo Volume Control.
 *
 *  Kashev Dalmia - kashev.dalmia@gmail.com
 *
 *  PGA2310.cpp
 */

#include "PGA2310.h"

PGA2310::PGA2310 (uint8_t pinCS, uint8_t pinSDATA, uint8_t pinSCLK, uint8_t pinZCEN, uint8_t pinMUTE)
{
    _pinCS    = pinCS;
    _pinSDATA = pinSDATA;
    _pinSCLK  = pinSCLK;
    _pinZCEN  = pinZCEN;
    _pinMUTE  = pinMUTE;

    _hard_mute = 1;
    _muted = 0;

    _v_left = _v_right = _pv_left = _pv_right = 0;

}

PGA2310::PGA2310 (uint8_t pinCS, uint8_t pinSDATA, uint8_t pinSCLK, uint8_t pinZCEN)
{
    _pinCS    = pinCS;
    _pinSDATA = pinSDATA;
    _pinSCLK  = pinSCLK;
    _pinZCEN  = pinZCEN;

    _hard_mute = 0;
    _muted = 0;

    _v_left = _v_right = _pv_left = _pv_right = 0;
}

void
PGA2310::begin (void)
{
    begin(1); /* By Default, Enable Zero Crossing Detection */
}

void
begin (uint8_t zcen_enable)
{
    pinMode(_pinCS,    OUTPUT);
    pinMode(_pinSDATA, OUTPUT);
    pinMode(_pinSCLK,  OUTPUT);
    pinMode(_pinZCEN,  OUTPUT);

    if (_hard_mute)
        pinMode(_pinMUTE, OUTPUT);

    if (zcen_enable)
        digitalWrite(_pinZCEN, HIGH);
    else
        digitalWrite(_pinZCEN, LOW);
}

uint8_t
PGA2310::getLeftVolume (void)
{
    return _v_left;
}

uint8_t
PGA2310::getRightVolume (void)
{
    return _v_right;
}

boolean
PGA2310::isMuted (void)
{
    return (boolean)_muted;
}

void
PGA2310::SPIWrite (uint8_t byte)
{
    for (uint8_t i = 0; i < 8; i++, byte <<= 1)
    {
        digitalWrite(_pinSCLK, LOW);
        if (0x80 & byte)
            digitalWrite(_pinSDATA, HIGH);
        else
            digitalWrite(_pinSDATA, LOW);
        digitalWrite(_pinSCLK, HIGH);
    }
}

void
PGA2310::setVolume (uint8_t left, uint8_t right)
{
    if ((left > MAX_GAIN) || (right > MAX_GAIN))
        return; /* don't allow gains above MAX_GAIN */

    digitalWrite(_pinCS, LOW);
    SPIWrite(right);
    SPIWrite(left);
    digitalWrite(_pinCS, HIGH);

    _pv_left = _v_left; _pv_right = _v_right;
    _v_left = left; _v_right = right;

    if (!(_hard_mute) && (_v_left == 0) && (_v_right == 0))
        _muted = 1;
}

void
PGA2310::setVolume (uint8_t vol)
{
    setVolume(vol, vol);
}

void
PGA2310::restoreVolume (void)
{
    uint8_t tr, tl;

    digitalWrite(_pinCS, LOW);
    SPIWrite(_pv_right);
    SPIWrite(_pv_left);
    digitalWrite(_pinCS, HIGH);

    tr = _v_right; tl = _v_left;

    _v_right = _pv_right; _v_left = _pv_left;
    _pv_right = tr; _pv_left = pl;
}

void
PGA2310::mute (void)
{
    if(_hard_mute)
        digitalWrite(_pinMUTE, LOW);
    else
        setVolume(0, 0);
    _muted = 1;
}

void
PGA2310::toggleMute (void)
{
    if (_muted)
    {
        /* unmute */
        if(_hard_mute)
            digitalWrite(_pinMUTE, HIGH);
        else
            restoreVolume();
        _muted = 0;
    }
    else
    {
        /* mute */
        if(_hard_mute)
            digitalWrite(_pinMUTE, LOW);
        else
            setVolume(0, 0);
        _muted = 1;
    }
}

void
PGA2310::incVolume (void)
{
    uint8_t nl, nr;

    if(_muted)
    {
        if (_hard_mute)
        {
            digitalWrite(_pinMUTE, HIGH);
        }
        _muted = 0;
    }

    nl = _v_left  == MAX_GAIN ? MAX_GAIN : _v_left  + 1;
    nr = _v_right == MAX_GAIN ? MAX_GAIN : _v_right + 1;

    if ((nl != _v_left) && (nr != _v_right))
    {
        /* minimize writes to device */
        setVolume(nl, nr);
    }
}

void
PGA2310::decVolume (void)
{
    uint8_t nl, nr;

    if(_muted)
    {
        if (_hard_mute)
        {
            digitalWrite(_pinMUTE, HIGH);
        }
        _muted = 0;
    }

    nl = _v_left  == 0 ? 0 : _v_left  - 1;
    nr = _v_right == 0 ? 0 : _v_right - 1;

    if ((nl != _v_left) && (nr != _v_right))
    {
        /* minimize writes to device */
        setVolume(nl, nr);
    }
}
<commit_msg>fixed compilation errors due to typos.<commit_after>/*
 *  ti-pga2310
 *  github.com/kashev/ti-pga2310
 *
 *      An Arduino / Energia Library for control of a Texas Instruments
 *      PGA2310 Stereo Volume Control.
 *
 *  Kashev Dalmia - kashev.dalmia@gmail.com
 *
 *  PGA2310.cpp
 */

#include "PGA2310.h"

PGA2310::PGA2310 (uint8_t pinCS, uint8_t pinSDATA, uint8_t pinSCLK, uint8_t pinZCEN, uint8_t pinMUTE)
{
    _pinCS    = pinCS;
    _pinSDATA = pinSDATA;
    _pinSCLK  = pinSCLK;
    _pinZCEN  = pinZCEN;
    _pinMUTE  = pinMUTE;

    _hard_mute = 1;
    _muted = 0;

    _v_left = _v_right = _pv_left = _pv_right = 0;

}

PGA2310::PGA2310 (uint8_t pinCS, uint8_t pinSDATA, uint8_t pinSCLK, uint8_t pinZCEN)
{
    _pinCS    = pinCS;
    _pinSDATA = pinSDATA;
    _pinSCLK  = pinSCLK;
    _pinZCEN  = pinZCEN;

    _hard_mute = 0;
    _muted = 0;

    _v_left = _v_right = _pv_left = _pv_right = 0;
}

void
PGA2310::begin (void)
{
    begin(1); /* By Default, Enable Zero Crossing Detection */
}

void
PGA2310::begin (uint8_t zcen_enable)
{
    pinMode(_pinCS,    OUTPUT);
    pinMode(_pinSDATA, OUTPUT);
    pinMode(_pinSCLK,  OUTPUT);
    pinMode(_pinZCEN,  OUTPUT);

    if (_hard_mute)
        pinMode(_pinMUTE, OUTPUT);

    if (zcen_enable)
        digitalWrite(_pinZCEN, HIGH);
    else
        digitalWrite(_pinZCEN, LOW);
}

uint8_t
PGA2310::getLeftVolume (void)
{
    return _v_left;
}

uint8_t
PGA2310::getRightVolume (void)
{
    return _v_right;
}

boolean
PGA2310::isMuted (void)
{
    return (boolean)_muted;
}

void
PGA2310::SPIWrite (uint8_t byte)
{
    for (uint8_t i = 0; i < 8; i++, byte <<= 1)
    {
        digitalWrite(_pinSCLK, LOW);
        if (0x80 & byte)
            digitalWrite(_pinSDATA, HIGH);
        else
            digitalWrite(_pinSDATA, LOW);
        digitalWrite(_pinSCLK, HIGH);
    }
}

void
PGA2310::setVolume (uint8_t left, uint8_t right)
{
    if ((left > MAX_GAIN) || (right > MAX_GAIN))
        return; /* don't allow gains above MAX_GAIN */

    digitalWrite(_pinCS, LOW);
    SPIWrite(right);
    SPIWrite(left);
    digitalWrite(_pinCS, HIGH);

    _pv_left = _v_left; _pv_right = _v_right;
    _v_left = left; _v_right = right;

    if (!(_hard_mute) && (_v_left == 0) && (_v_right == 0))
        _muted = 1;
}

void
PGA2310::setVolume (uint8_t vol)
{
    setVolume(vol, vol);
}

void
PGA2310::restoreVolume (void)
{
    uint8_t tr, tl;

    digitalWrite(_pinCS, LOW);
    SPIWrite(_pv_right);
    SPIWrite(_pv_left);
    digitalWrite(_pinCS, HIGH);

    tr = _v_right; tl = _v_left;

    _v_right = _pv_right; _v_left = _pv_left;
    _pv_right = tr; _pv_left = tl;
}

void
PGA2310::mute (void)
{
    if(_hard_mute)
        digitalWrite(_pinMUTE, LOW);
    else
        setVolume(0, 0);
    _muted = 1;
}

void
PGA2310::toggleMute (void)
{
    if (_muted)
    {
        /* unmute */
        if(_hard_mute)
            digitalWrite(_pinMUTE, HIGH);
        else
            restoreVolume();
        _muted = 0;
    }
    else
    {
        /* mute */
        if(_hard_mute)
            digitalWrite(_pinMUTE, LOW);
        else
            setVolume(0, 0);
        _muted = 1;
    }
}

void
PGA2310::incVolume (void)
{
    uint8_t nl, nr;

    if(_muted)
    {
        if (_hard_mute)
        {
            digitalWrite(_pinMUTE, HIGH);
        }
        _muted = 0;
    }

    nl = _v_left  == MAX_GAIN ? MAX_GAIN : _v_left  + 1;
    nr = _v_right == MAX_GAIN ? MAX_GAIN : _v_right + 1;

    if ((nl != _v_left) && (nr != _v_right))
    {
        /* minimize writes to device */
        setVolume(nl, nr);
    }
}

void
PGA2310::decVolume (void)
{
    uint8_t nl, nr;

    if(_muted)
    {
        if (_hard_mute)
        {
            digitalWrite(_pinMUTE, HIGH);
        }
        _muted = 0;
    }

    nl = _v_left  == 0 ? 0 : _v_left  - 1;
    nr = _v_right == 0 ? 0 : _v_right - 1;

    if ((nl != _v_left) && (nr != _v_right))
    {
        /* minimize writes to device */
        setVolume(nl, nr);
    }
}
<|endoftext|>


<commit_before>#include <cstring>
#include <iostream>

#include <UnitTest++.h>
#include <TestReporter.h> // Part of UnitTest++
#include <tightdb.hpp>
#include <tightdb/column.hpp>
#include <tightdb/utilities.hpp>
#include <tightdb/query_engine.hpp>
#include <assert.h>

#define USE_VLD
#if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_VLD)
    #include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
#endif

using namespace std;
using namespace UnitTest;
using namespace tightdb;

namespace {

struct CustomTestReporter: TestReporter {
    void ReportTestStart(TestDetails const& test)
    {
        static_cast<void>(test);
//        cerr << test.filename << ":" << test.lineNumber << ": Begin " << test.testName << "\n";
    }

    void ReportFailure(TestDetails const& test, char const* failure)
    {
        cerr << test.filename << ":" << test.lineNumber << ": error: "
            "Failure in " << test.testName << ": " << failure << "\n";
    }

    void ReportTestFinish(TestDetails const& test, float seconds_elapsed)
    {
        static_cast<void>(test);
        static_cast<void>(seconds_elapsed);
//        cerr << test.filename << ":" << test.lineNumber << ": End\n";
    }

    void ReportSummary(int total_test_count, int failed_test_count, int failure_count, float seconds_elapsed)
    {
        if (0 < failure_count)
            cerr << "FAILURE: " << failed_test_count << " "
                "out of " << total_test_count << " tests failed "
                "(" << failure_count << " failures).\n";
        else
            cerr << "Success: " << total_test_count << " tests passed.\n";

        const streamsize orig_prec = cerr.precision();
        cerr.precision(2);
        cerr << "Test time: " << seconds_elapsed << " seconds.\n";
        cerr.precision(orig_prec);
    }
};

} // anonymous namespace

TIGHTDB_TABLE_3(ThreeColTable,
    first,  Int,
    second, Float,
    third, Double)

int main(int argc, char* argv[])
{
    size_t match;

    // Setup untyped table
    Table untyped;
    untyped.add_column(type_Int, "firs1");
    untyped.add_column(type_Float, "second");
    untyped.add_column(type_Double, "third");
    untyped.add_empty_row(2);
    untyped.set_int(0, 0, 20);
    untyped.set_float(1, 0, 19.9f);
    untyped.set_double(2, 0, 3.0);
    untyped.set_int(0, 1, 20);
    untyped.set_float(1, 1, 20.1f);
    untyped.set_double(2, 1, 4.0);

    // Setup typed table, same contents as untyped
    ThreeColTable typed;
    typed.add(20, 19.9f, 3.0);
    typed.add(20, 20.1f, 4.0);

    // Testing &&

    // Left condition makes first row non-match
    match = (untyped.column<float>(1) + 1 > 21 && untyped.column<double>(2) > 2).find_next();
    assert(match == 1);

    // Right condition makes first row a non-match
    match = (untyped.column<float>(1) > 10 && untyped.column<double>(2) > 3.5).find_next();
    assert(match == 1);

    // Both make first row match
    match = (untyped.column<float>(1) < 20 && untyped.column<double>(2) > 2).find_next();
    assert(match == 0);

    // Both make first row non-match
    match = (untyped.column<float>(1) > 20 && untyped.column<double>(2) > 3.5).find_next();
    assert(match == 1);

    // Left cond match 0, right match 1
    match = (untyped.column<float>(1) < 20 && untyped.column<double>(2) > 3.5).find_next();
    assert(match == not_found);

    // Left match 1, right match 0
    match = (untyped.column<float>(1) > 20 && untyped.column<double>(2) < 3.5).find_next();
    assert(match == not_found);

    // Testing ||

    // Left match 0
    match = (untyped.column<float>(1) < 20 || untyped.column<double>(2) < 3.5).find_next();
    assert(match == 0);

    // Right match 0
    match = (untyped.column<float>(1) > 20 || untyped.column<double>(2) < 3.5).find_next();
    assert(match == 0);

    // Left match 1

    match = (untyped.column<float>(1) > 20 || untyped.column<double>(2) > 9.5).find_next();

    assert(match == 1);

    // Tons of other tests. More in test_query.cpp

    Query q4 = untyped.column<float>(1) + untyped.column<int64_t>(0) > 40;
    Query q5 = 20 < untyped.column<float>(1);

    match = q4.expression(  q5.get_expression()  ).find_next();
    assert(match == 1);

    // Untyped, direct column addressing
    Value<int64_t> uv1(1);

    Columns<float> uc1 = untyped.column<float>(1);

    Query q2 = uv1 <= uc1;
    match = q2.find_next();
    assert(match == 0);

    Query q0 = uv1 <= uc1;
    match = q0.find_next();
    assert(match == 0);

    Query q99 = uv1 <= untyped.column<float>(1);
    match = q99.find_next();
    assert(match == 0);

    Query q8 = 1 > untyped.column<float>(1) + 5;
    match = q8.find_next();
    assert(match == not_found);

    Query q3 = untyped.column<float>(1) + untyped.column<int64_t>(0) > 10 + untyped.column<int64_t>(0);
    match = q3.find_next();

    match = q2.find_next();
    assert(match == 0);

    // Typed, direct column addressing
    Query q1 = typed.column().second + typed.column().first > 40;
    match = q1.find_next();
    assert(match == 1);

    match = (typed.column().first + typed.column().second > 40).find_next();
    assert(match == 1);

    Query tq1 = typed.column().first + typed.column().second >= typed.column().first + typed.column().second;
    match = tq1.find_next();
    assert(match == 0);

    // Typed, column objects
    Columns<int64_t> t0 = typed.column().first;
    Columns<float> t1 = typed.column().second;

    match = (t0 + t1 > 40).find_next();
    assert(match == 1);

    match = q1.find_next();
    assert(match == 1);

    match = (untyped.column<int64_t>(0) + untyped.column<float>(1) > 40).find_next();
    assert(match == 1);

    match = (untyped.column<int64_t>(0) + untyped.column<float>(1) < 40).find_next();
    assert(match == 0);

    match = (untyped.column<float>(1) <= untyped.column<int64_t>(0)).find_next();
    assert(match == 0);

    match = (untyped.column<int64_t>(0) + untyped.column<float>(1) >= untyped.column<int64_t>(0) + untyped.column<float>(1)).find_next();
    assert(match == 0);

    // Untyped, column objects
    Columns<int64_t> u0 = untyped.column<int64_t>(0);
    Columns<float> u1 = untyped.column<float>(1);

    match = (u0 + u1 > 40).find_next();
    assert(match == 1);

    // Flexible language binding style
    Subexpr* first = new Columns<int64_t>(0);
    Subexpr* second = new Columns<float>(1);
    Subexpr* third = new Columns<double>(2);
    Subexpr* constant = new Value<int64_t>(40);
    Subexpr* plus = new Operator<Plus<float> >(*first, *second);
    Expression *e = new Compare<Greater, float>(*plus, *constant);

    // Bind table and do search
    match = untyped.where().expression(e).find_next();
    assert(match == 1);

    Query q9 = untyped.where().expression(e);
    match = q9.find_next();
    assert(match == 1);

    Subexpr* first2 = new Columns<int64_t>(0);
    Subexpr* second2 = new Columns<float>(1);
    Subexpr* third2 = new Columns<double>(2);
    Subexpr* constant2 = new Value<int64_t>(40);
    Subexpr* plus2 = new Operator<Plus<float> >(*first, *second);
    Expression *e2 = new Compare<Greater, float>(*plus, *constant);

    match = untyped.where().expression(e).expression(e2).find_next();
    assert(match == 1);

    Query q10 = untyped.where().expression(q9.get_expression()).expression(e2);
    match = q10.find_next();
    assert(match == 1);

    Query tq3 = tq1;
    match = tq3.find_next();
    assert(match == 0);

    delete e;
    delete plus;
    delete constant;
    delete third;
    delete second;
    delete first;

    delete e2;
    delete plus2;
    delete constant2;
    delete third2;
    delete second2;
    delete first2;

    CustomTestReporter reporter;
    TestRunner runner(reporter);
    const int res = runner.RunTestsIf(Test::GetTestList(), 0, True(), 0);

    return 0;
}

// 638

// 545   568<commit_msg>main.cpp demo<commit_after>#include <cstring>
#include <iostream>

#include <UnitTest++.h>
#include <TestReporter.h> // Part of UnitTest++
#include <tightdb.hpp>
#include <tightdb/column.hpp>
#include <tightdb/utilities.hpp>
#include <tightdb/query_engine.hpp>
#include <assert.h>

#define USE_VLD
#if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_VLD)
    #include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
#endif

using namespace std;
using namespace UnitTest;
using namespace tightdb;

namespace {

struct CustomTestReporter: TestReporter {
    void ReportTestStart(TestDetails const& test)
    {
        static_cast<void>(test);
//        cerr << test.filename << ":" << test.lineNumber << ": Begin " << test.testName << "\n";
    }

    void ReportFailure(TestDetails const& test, char const* failure)
    {
        cerr << test.filename << ":" << test.lineNumber << ": error: "
            "Failure in " << test.testName << ": " << failure << "\n";
    }

    void ReportTestFinish(TestDetails const& test, float seconds_elapsed)
    {
        static_cast<void>(test);
        static_cast<void>(seconds_elapsed);
//        cerr << test.filename << ":" << test.lineNumber << ": End\n";
    }

    void ReportSummary(int total_test_count, int failed_test_count, int failure_count, float seconds_elapsed)
    {
        if (0 < failure_count)
            cerr << "FAILURE: " << failed_test_count << " "
                "out of " << total_test_count << " tests failed "
                "(" << failure_count << " failures).\n";
        else
            cerr << "Success: " << total_test_count << " tests passed.\n";

        const streamsize orig_prec = cerr.precision();
        cerr.precision(2);
        cerr << "Test time: " << seconds_elapsed << " seconds.\n";
        cerr.precision(orig_prec);
    }
};

} // anonymous namespace

TIGHTDB_TABLE_3(ThreeColTable,
    first,  Int,
    second, Float,
    third, Double)

int main(int argc, char* argv[])
{
    size_t match;

    // Setup untyped table
    Table untyped;
    untyped.add_column(type_Int, "firs1");
    untyped.add_column(type_Float, "second");
    untyped.add_column(type_Double, "third");
    untyped.add_empty_row(2);
    untyped.set_int(0, 0, 20);
    untyped.set_float(1, 0, 19.9f);
    untyped.set_double(2, 0, 3.0);
    untyped.set_int(0, 1, 20);
    untyped.set_float(1, 1, 20.1f);
    untyped.set_double(2, 1, 4.0);

    // Setup typed table, same contents as untyped
    ThreeColTable typed;
    typed.add(20, 19.9f, 3.0);
    typed.add(20, 20.1f, 4.0);

    // Small typed table test:
    match = (typed.column().second + 100 > 120 && typed.column().first > 2).find_next();
    assert(match == 1);

    // Untyped &&

    // Left condition makes first row non-match
    match = (untyped.column<float>(1) + 1 > 21 && untyped.column<double>(2) > 2).find_next();
    assert(match == 1);

    // Right condition makes first row a non-match
    match = (untyped.column<float>(1) > 10 && untyped.column<double>(2) > 3.5).find_next();
    assert(match == 1);

    // Both make first row match
    match = (untyped.column<float>(1) < 20 && untyped.column<double>(2) > 2).find_next();
    assert(match == 0);

    // Both make first row non-match
    match = (untyped.column<float>(1) > 20 && untyped.column<double>(2) > 3.5).find_next();
    assert(match == 1);

    // Left cond match 0, right match 1
    match = (untyped.column<float>(1) < 20 && untyped.column<double>(2) > 3.5).find_next();
    assert(match == not_found);

    // Left match 1, right match 0
    match = (untyped.column<float>(1) > 20 && untyped.column<double>(2) < 3.5).find_next();
    assert(match == not_found);

    // Untyped ||

    // Left match 0
    match = (untyped.column<float>(1) < 20 || untyped.column<double>(2) < 3.5).find_next();
    assert(match == 0);

    // Right match 0
    match = (untyped.column<float>(1) > 20 || untyped.column<double>(2) < 3.5).find_next();
    assert(match == 0);

    // Left match 1

    match = (untyped.column<float>(1) > 20 || untyped.column<double>(2) > 9.5).find_next();

    assert(match == 1);

    // Tons of other tests. More in test_query.cpp

    Query q4 = untyped.column<float>(1) + untyped.column<int64_t>(0) > 40;
    Query q5 = 20 < untyped.column<float>(1);

    match = q4.expression(  q5.get_expression()  ).find_next();
    assert(match == 1);

    // Untyped, direct column addressing
    Value<int64_t> uv1(1);

    Columns<float> uc1 = untyped.column<float>(1);

    Query q2 = uv1 <= uc1;
    match = q2.find_next();
    assert(match == 0);

    Query q0 = uv1 <= uc1;
    match = q0.find_next();
    assert(match == 0);

    Query q99 = uv1 <= untyped.column<float>(1);
    match = q99.find_next();
    assert(match == 0);

    Query q8 = 1 > untyped.column<float>(1) + 5;
    match = q8.find_next();
    assert(match == not_found);

    Query q3 = untyped.column<float>(1) + untyped.column<int64_t>(0) > 10 + untyped.column<int64_t>(0);
    match = q3.find_next();

    match = q2.find_next();
    assert(match == 0);

    // Typed, direct column addressing
    Query q1 = typed.column().second + typed.column().first > 40;
    match = q1.find_next();
    assert(match == 1);

    match = (typed.column().first + typed.column().second > 40).find_next();
    assert(match == 1);

    Query tq1 = typed.column().first + typed.column().second >= typed.column().first + typed.column().second;
    match = tq1.find_next();
    assert(match == 0);

    // Typed, column objects
    Columns<int64_t> t0 = typed.column().first;
    Columns<float> t1 = typed.column().second;

    match = (t0 + t1 > 40).find_next();
    assert(match == 1);

    match = q1.find_next();
    assert(match == 1);

    match = (untyped.column<int64_t>(0) + untyped.column<float>(1) > 40).find_next();
    assert(match == 1);

    match = (untyped.column<int64_t>(0) + untyped.column<float>(1) < 40).find_next();
    assert(match == 0);

    match = (untyped.column<float>(1) <= untyped.column<int64_t>(0)).find_next();
    assert(match == 0);

    match = (untyped.column<int64_t>(0) + untyped.column<float>(1) >= untyped.column<int64_t>(0) + untyped.column<float>(1)).find_next();
    assert(match == 0);

    // Untyped, column objects
    Columns<int64_t> u0 = untyped.column<int64_t>(0);
    Columns<float> u1 = untyped.column<float>(1);

    match = (u0 + u1 > 40).find_next();
    assert(match == 1);

    // Flexible language binding style
    Subexpr* first = new Columns<int64_t>(0);
    Subexpr* second = new Columns<float>(1);
    Subexpr* third = new Columns<double>(2);
    Subexpr* constant = new Value<int64_t>(40);
    Subexpr* plus = new Operator<Plus<float> >(*first, *second);
    Expression *e = new Compare<Greater, float>(*plus, *constant);

    // Bind table and do search
    match = untyped.where().expression(e).find_next();
    assert(match == 1);

    Query q9 = untyped.where().expression(e);
    match = q9.find_next();
    assert(match == 1);

    Subexpr* first2 = new Columns<int64_t>(0);
    Subexpr* second2 = new Columns<float>(1);
    Subexpr* third2 = new Columns<double>(2);
    Subexpr* constant2 = new Value<int64_t>(40);
    Subexpr* plus2 = new Operator<Plus<float> >(*first, *second);
    Expression *e2 = new Compare<Greater, float>(*plus, *constant);

    match = untyped.where().expression(e).expression(e2).find_next();
    assert(match == 1);

    Query q10 = untyped.where().expression(q9.get_expression()).expression(e2);
    match = q10.find_next();
    assert(match == 1);

    Query tq3 = tq1;
    match = tq3.find_next();
    assert(match == 0);

    delete e;
    delete plus;
    delete constant;
    delete third;
    delete second;
    delete first;

    delete e2;
    delete plus2;
    delete constant2;
    delete third2;
    delete second2;
    delete first2;

    CustomTestReporter reporter;
    TestRunner runner(reporter);
    const int res = runner.RunTestsIf(Test::GetTestList(), 0, True(), 0);

    return 0;
}

// 638

// 545   568<|endoftext|>


<commit_before>//
// Created by Martin Miralles-Cordal on 5/16/2018.
//

#pragma once

#include <util/TypeTraits.hpp>
#include <util/Void.hpp>

#include <concepts>
#include <cstdint>
#include <functional>
#include <iterator>

namespace sys {

template <typename T>
class Maybe
{
  public:
    // our custom types
    using RegularType = regular_t<T>;
    template <bool Const> struct BasicIterator;
    using RawType = typename std::decay<RegularType>::type;
    using MutableType = typename std::remove_const<RegularType>::type;

    // std container member types
    using iterator = BasicIterator<false>;
    using const_iterator = BasicIterator<true>;
    using value_type = std::remove_reference_t<RegularType>;
    using reference = lvref_t<value_type>;
    using const_reference = cref_t<value_type>;
    using rvalue_reference = rvref_t<value_type>;
    using pointer = value_type *;
    using const_pointer = value_type const *;
    using difference_type = int64_t;
    using size_type = size_t;

    constexpr Maybe() = default;
    constexpr Maybe(Void) : Maybe() {}

    template <std::copy_constructible U = T>
    constexpr Maybe(T const &v) : _store(v), _set(true) {}

    template <std::move_constructible U = T>
    constexpr Maybe(T &&v) : _store(std::move(v)), _set(true) {}

    constexpr Maybe(Maybe const &other) : _store{}, _set(other._set) { if (_set) { _store.init(other.ref_()); } }
    constexpr Maybe& operator=(Maybe const &other) = delete;

    /** Move constructor. */
    constexpr Maybe(Maybe&& other) : _store{}, _set(other._set)
    {
        if (_set) { _store.init(std::move(other.takeValue_())); other.clear(); }
    }
    constexpr Maybe& operator=(Maybe &&other) = delete;

    /** Clears the stored value. */
    constexpr void clear() { _store.destroy(_set); _set = false; }

    /** Returns whether this contains a value. */
    constexpr operator bool() const noexcept { return _set; }

    /** Returns whether this contains a value. */
    constexpr bool isPresent() const noexcept { return _set; }

    /**
     * Accesses the contained value.
     * @return A const pointer to the value if set, nullptr otherwise.
     */
    constexpr value_type const * operator->() const { return _set ? &ref_() : nullptr; }

    /**
     * Accesses the contained value.
     * @return A pointer to the value if set, nullptr otherwise.
     */
    constexpr value_type * operator->() { return _set ? &ref_() : nullptr; }

    /**
     * Accesses the contained value.
     * @return A const ref to the value. Return value is undefined if not set.
     */
    constexpr value_type const & operator*() const { return ref_(); }

    /**
     * Accesses the contained value.
     * @return A reference to the value. Return value is undefined if not set.
     */
    constexpr value_type & operator*() { return ref_(); }

    /**
     * Returns the contained value.
     * @return A const ref to the value. Return value is undefined if not set.
     */
    constexpr value_type const & get() const { return ref_(); }

    /**
     * Returns the contained value.
     * @return A reference to the value. Return value is undefined if not set.
     */
    constexpr value_type & get() { return ref_(); }

    /**
     * Returns a copy of the contained value, or a default value if not set.
     * @param other The value to default to.
     * @return A copy of the value, or the default value if this is not set.
     */
    constexpr value_type getOr(T &&other) const &
    {
        return _set ? ref_() : std::forward<T>(other);
    }

    /**
     * Moves out the contained value or returns a default value if not set.
     * @param other The value to default to.
     * @return A copy of the value, or the default value if this is not set.
     */
    constexpr value_type getOr(T &&other) &&
    {
        return _set ? std::move(takeValue_()) : std::forward<T>(other);
    }

    /** @name STL container interface */
    /** @{ */

    constexpr bool empty() const { return empty(); }
    constexpr size_type size() const { return isPresent() ? 1 : 0; }
    constexpr size_type max_size() const { return 1; }

    constexpr const_iterator cbegin() const { return isPresent() ? const_iterator{this} : cend(); }
    constexpr const_iterator cend() const { return const_iterator{this, const_iterator::kEndIterator}; }
    constexpr const_iterator begin() const { return cbegin(); }
    constexpr const_iterator end() const { return cend(); }
    constexpr iterator begin() { return isPresent() ? iterator{this} : end(); }
    constexpr iterator end() { return iterator{this, iterator::kEndIterator}; }

    constexpr reference front() { return get(); }
    constexpr const_reference front() const { return get(); }
    constexpr reference back() { return get(); }
    constexpr const_reference back() const { return get(); }

    /** @} */

  private:
    inline constexpr decltype(auto) takeValue_() noexcept { return _store.rvRef(); }
    inline constexpr decltype(auto) ref_() noexcept { return _store.ref(); }
    inline constexpr decltype(auto) ref_() const noexcept { return _store.ref(); }

    template<typename Ts>
    union Storage
    {
        constexpr Storage() : _nothing() {}
        constexpr Storage(Ts const &aValue) : _value(aValue) {}
        constexpr Storage(Ts &&aValue) : _value(std::move(aValue)) {}
        ~Storage() {}

        constexpr void destroy(bool isSet) { if (isSet) { _value.~Ts(); } }
        constexpr void init(const Ts &val) { new (&_value) Ts{val}; }
        constexpr void init(Ts &&val) { new (&_value) Ts{std::move(val)}; }

        constexpr value_type&& rvRef() noexcept { return std::move(_value); }

        constexpr value_type& ref() noexcept { return _value; }
        constexpr value_type const & ref() const noexcept { return _value; }

      private:
        Void _nothing;
        Ts _value;
    };

    template<typename Ts>
    union Storage<Ts &>
    {
        constexpr Storage()  noexcept : _nothing() {}
        constexpr Storage(reference aValue) noexcept : _value(&aValue) {}

        constexpr void destroy(bool) noexcept {}
        constexpr void init(reference val) noexcept { _value = val; }
        constexpr auto rvRef() noexcept { return _value.get(); }
        constexpr value_type& ref() const noexcept { return _value.get(); }

      private:
        Void _nothing;
        std::reference_wrapper<value_type> _value;
    };

    Storage<MutableType> _store{};
    bool _set{false};
  public:
    template <bool Const>
    struct BasicIterator
    {
        static constexpr const bool kValueIterator = false;
        static constexpr const bool kEndIterator = true;
        using iterator_category = std::bidirectional_iterator_tag;
        using value_type = RegularType;
        using difference_type = Maybe::difference_type;
        using reference = const_t<RegularType, Const>;
        using pointer = typename std::conditional<Const, RegularType const *, RegularType *>::type;

        // maintain is_trivially_copy_constructible by defining the Iterator->ConstIterator constructor as a template.
        template <bool OtherConst, typename = typename std::enable_if<Const || !OtherConst>::type>
        constexpr BasicIterator(const BasicIterator<OtherConst> &other) : parent_(other.parent_), end_(other.end_) {}

        explicit BasicIterator(const_ptr_t<Maybe, Const> parent) : parent_(parent), end_(kValueIterator) {}
        constexpr BasicIterator(const_ptr_t<Maybe, Const> parent, bool end) : parent_(parent), end_(end) {}

        constexpr reference operator*() const { return parent_->GetValue(); }

        constexpr BasicIterator& operator++() { end_ = true; return *this; }
        constexpr BasicIterator operator++(int) { auto copy = *this; operator++(); return copy; }
        constexpr BasicIterator& operator--() { end_ = false; return *this; }
        constexpr BasicIterator operator--(int) { auto copy = *this; operator--(); return copy; }

        constexpr bool operator==(BasicIterator const &rhs) const { return parent_ == rhs.parent_ && end_ == rhs.end_; }
        constexpr bool operator!=(BasicIterator const &rhs) const { return !(rhs == *this); }

        constexpr bool end() const { return end_; }

      private:
        const_ptr_t<Maybe, Const> parent_;
        bool end_;
    };
};

template <typename T> Maybe(T const &) -> Maybe<T>;
template <typename T> Maybe(T &&) -> Maybe<T>;

/**
 * Constructs and "promotes" an object to a Maybe<T>.
 * @tparam T The type of Maybe.
 * @tparam Args The types for one of T's constructors. (deducible)
 * @param args The arguments for one of T's constructors.
 * @return The Maybe.
 */
template <typename T, typename... Args>
constexpr static Maybe<T> AsMaybe(Args && ...args)
{
    return Maybe<T>(T(std::forward<Args>(args)...));
}

} // libsys namespace
<commit_msg>Maybe<T> support for reassignment.<commit_after>//
// Created by Martin Miralles-Cordal on 5/16/2018.
//

#pragma once

#include <util/TypeTraits.hpp>
#include <util/Void.hpp>

#include <concepts>
#include <cstdint>
#include <functional>
#include <iterator>

namespace sys {

template <typename T>
class Maybe
{
  public:
    // our custom types
    using RegularType = regular_t<T>;
    template <bool Const> struct BasicIterator;
    using RawType = typename std::decay<RegularType>::type;
    using MutableType = typename std::remove_const<RegularType>::type;

    // std container member types
    using iterator = BasicIterator<false>;
    using const_iterator = BasicIterator<true>;
    using value_type = std::remove_reference_t<RegularType>;
    using reference = lvref_t<value_type>;
    using const_reference = cref_t<value_type>;
    using rvalue_reference = rvref_t<value_type>;
    using pointer = value_type *;
    using const_pointer = value_type const *;
    using difference_type = int64_t;
    using size_type = size_t;

    constexpr Maybe() = default;
    constexpr Maybe(Void) : Maybe() {}

    template <std::copy_constructible U = T>
    constexpr Maybe(T const &v) : _store(v), _set(true) {}

    template <std::move_constructible U = T>
    constexpr Maybe(T &&v) : _store(std::move(v)), _set(true) {}

    constexpr Maybe(Maybe const &other) : _store{}, _set(other._set) { if (_set) { _store.init(other.ref_()); } }

    /** Copy assignment operator */
    Maybe& operator=(Maybe const &other)
    {
        if (other._set) { set(other.ref_()); }
        else { clear(); }
        return *this;
    }

    /** Move constructor. */
    constexpr Maybe(Maybe&& other) : _store{}, _set(other._set)
    {
        if (_set) { _store.init(std::move(other).ref_()); other.clear(); }
    }

    /** Move assignment operator */
    Maybe& operator=(Maybe &&other)
    {
        if (other._set) { set(std::move(other).ref_()); other.clear(); }
        else { clear(); }
        return *this;
    }

    /** Clears the stored value. */
    constexpr void clear() { _store.destroy(_set); _set = false; }

    /** Returns whether this contains a value. */
    constexpr operator bool() const noexcept { return _set; }

    /** Returns whether this contains a value. */
    constexpr bool isPresent() const noexcept { return _set; }

    /**
     * Accesses the contained value.
     * @return A const pointer to the value if set, nullptr otherwise.
     */
    constexpr value_type const * operator->() const { return _set ? &ref_() : nullptr; }

    /**
     * Accesses the contained value.
     * @return A pointer to the value if set, nullptr otherwise.
     */
    constexpr value_type * operator->() { return _set ? &ref_() : nullptr; }

    /**
     * Accesses the contained value.
     * @return A const ref to the value. Return value is undefined if not set.
     */
    constexpr value_type const & operator*() const { return ref_(); }

    /**
     * Accesses the contained value.
     * @return A reference to the value. Return value is undefined if not set.
     */
    constexpr value_type & operator*() { return ref_(); }

    /**
     * Returns the contained value.
     * @return A const ref to the value. Return value is undefined if not set.
     */
    constexpr value_type const & get() const { return ref_(); }

    /**
     * Returns the contained value.
     * @return A reference to the value. Return value is undefined if not set.
     */
    constexpr value_type & get() { return ref_(); }

    /**
     * Returns a copy of the contained value, or a default value if not set.
     * @param other The value to default to.
     * @return A copy of the value, or the default value if this is not set.
     */
    constexpr value_type getOr(T &&other) const &
    {
        return _set ? ref_() : std::forward<T>(other);
    }

    /**
     * Moves out the contained value or returns a default value if not set.
     * @param other The value to default to.
     * @return A copy of the value, or the default value if this is not set.
     */
    constexpr value_type getOr(T &&other) &&
    {
        return _set ? std::move(*this).ref_() : std::forward<T>(other);
    }

    /** Sets the Maybe to a copy of the given value. */
    constexpr void set(const_reference value)
    {
        if (_set) { _store.reassign(value); }
        else { _store.init(value); }
        _set = true;
    }

    /** Sets the Maybe by moving the given value into the storage. */
    constexpr void set(rvalue_reference value)
    {
        if (_set) { _store.reassign(std::move(value)); }
        else { _store.init(std::move(value)); }
        _set = true;
    }

    /** @name STL container interface */
    /** @{ */

    constexpr bool empty() const { return empty(); }
    constexpr size_type size() const { return isPresent() ? 1 : 0; }
    constexpr size_type max_size() const { return 1; }

    constexpr const_iterator cbegin() const { return isPresent() ? const_iterator{this} : cend(); }
    constexpr const_iterator cend() const { return const_iterator{this, const_iterator::kEndIterator}; }
    constexpr const_iterator begin() const { return cbegin(); }
    constexpr const_iterator end() const { return cend(); }
    constexpr iterator begin() { return isPresent() ? iterator{this} : end(); }
    constexpr iterator end() { return iterator{this, iterator::kEndIterator}; }

    constexpr reference front() { return get(); }
    constexpr const_reference front() const { return get(); }
    constexpr reference back() { return get(); }
    constexpr const_reference back() const { return get(); }

    /** @} */

  private:
    inline constexpr decltype(auto) ref_() && noexcept { return std::move(_store).ref(); }
    inline constexpr decltype(auto) ref_() const && noexcept { return std::move(_store).ref(); }
    inline constexpr decltype(auto) ref_() &  noexcept{ return _store.ref(); }
    inline constexpr decltype(auto) ref_() const & noexcept{ return _store.ref(); }

    template<typename Ts>
    union Storage
    {
        constexpr Storage() : _nothing() {}
        constexpr Storage(Ts const &aValue) : _value(aValue) {}
        constexpr Storage(Ts &&aValue) : _value(std::move(aValue)) {}
        ~Storage() {}

        constexpr void destroy(bool isSet) { if (isSet) { _value.~Ts(); } }
        constexpr void init(const Ts &val) { new (&_value) Ts{val}; }
        constexpr void init(Ts &&val) { new (&_value) Ts{std::move(val)}; }

        template <std::same_as<Ts> Us = Ts> requires std::copy_assignable<Us>
        constexpr void reassign(const Ts &val) { _value = val; }

        template <std::same_as<Ts> Us = Ts> requires (!std::copy_assignable<Us> && std::copy_constructible<Us>)
        constexpr void reassign(const Ts &val) { destroy(true); init(val); }

        template <std::same_as<Ts> Us = Ts> requires std::move_assignable<Us>
        constexpr void reassign(Ts &&val) { _value = std::move(val); }

        template <std::same_as<Ts> Us = Ts> requires (std::move_constructible<Us> && !std::move_assignable<Us>)
        constexpr void reassign(Ts &&val) { destroy(true); init(std::move(val)); }

        constexpr value_type&& ref() && noexcept { return std::move(_value); }
        constexpr value_type&& ref() const && noexcept { return std::move(_value); }

        constexpr value_type& ref() & noexcept { return _value; }
        constexpr value_type const & ref() const & noexcept { return _value; }

      private:
        Void _nothing;
        Ts _value;
    };

    template<typename Ts>
    union Storage<Ts &>
    {
        constexpr Storage()  noexcept : _nothing() {}
        constexpr Storage(reference aValue) noexcept : _value(&aValue) {}

        constexpr void destroy(bool) noexcept {}
        constexpr void init(reference val) noexcept { _value = val; }
        void reassign(reference val) noexcept { _value = val; }

        constexpr value_type& ref() const && noexcept { return _value.get(); }
        constexpr value_type& ref() const & noexcept { return _value.get(); }

      private:
        Void _nothing;
        std::reference_wrapper<value_type> _value;
    };

    Storage<MutableType> _store{};
    bool _set{false};

  public:
    template <bool Const>
    struct BasicIterator
    {
        static constexpr const bool kValueIterator = false;
        static constexpr const bool kEndIterator = true;
        using iterator_category = std::bidirectional_iterator_tag;
        using value_type = RegularType;
        using difference_type = Maybe::difference_type;
        using reference = const_t<RegularType, Const>;
        using pointer = typename std::conditional<Const, RegularType const *, RegularType *>::type;

        // maintain is_trivially_copy_constructible by defining the Iterator->ConstIterator constructor as a template.
        template <bool OtherConst, typename = typename std::enable_if<Const || !OtherConst>::type>
        constexpr BasicIterator(const BasicIterator<OtherConst> &other) : parent_(other.parent_), end_(other.end_) {}

        explicit BasicIterator(const_ptr_t<Maybe, Const> parent) : parent_(parent), end_(kValueIterator) {}
        constexpr BasicIterator(const_ptr_t<Maybe, Const> parent, bool end) : parent_(parent), end_(end) {}

        constexpr reference operator*() const { return parent_->GetValue(); }

        constexpr BasicIterator& operator++() { end_ = true; return *this; }
        constexpr BasicIterator operator++(int) { auto copy = *this; operator++(); return copy; }
        constexpr BasicIterator& operator--() { end_ = false; return *this; }
        constexpr BasicIterator operator--(int) { auto copy = *this; operator--(); return copy; }

        constexpr bool operator==(BasicIterator const &rhs) const { return parent_ == rhs.parent_ && end_ == rhs.end_; }
        constexpr bool operator!=(BasicIterator const &rhs) const { return !(rhs == *this); }

        constexpr bool end() const { return end_; }

      private:
        const_ptr_t<Maybe, Const> parent_;
        bool end_;
    };
};

template <typename T> Maybe(T const &) -> Maybe<T>;
template <typename T> Maybe(T &&) -> Maybe<T>;

/**
 * Constructs and "promotes" an object to a Maybe<T>.
 * @tparam T The type of Maybe.
 * @tparam Args The types for one of T's constructors. (deducible)
 * @param args The arguments for one of T's constructors.
 * @return The Maybe.
 */
template <typename T, typename... Args>
constexpr static Maybe<T> AsMaybe(Args && ...args)
{
    return Maybe<T>(T(std::forward<Args>(args)...));
}

} // libsys namespace
<|endoftext|>