ezc/src/var.h

1038 lines
19 KiB
C++

/*
* This file is a part of EZC -- Easy templating in C++ library
* and is distributed under the BSD 3-Clause licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2021-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name Tomasz Sowa nor the names of contributors to this
* project may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef headerfile_ezc_var
#define headerfile_ezc_var
#include "spacewrapper.h"
#include "date/date.h"
#include "modelcontainerwrapper.h"
#include "textstream/textstream.h"
namespace morm
{
class Model;
}
namespace Ezc
{
template<typename StreamType>
struct Env;
/*
a variable
*/
template<typename StreamType>
class Var
{
public:
typedef void (*UserFunction)(Env<StreamType> &);
enum Type
{
TYPE_VOID,
TYPE_SPACE_LOCAL,
TYPE_STREAM,
TYPE_FUNCTION,
TYPE_DATE,
TYPE_MODEL,
TYPE_MODEL_CONTAINER_WRAPPER,
TYPE_SPACE_WRAPPER,
TYPE_SPACE,
};
Var();
Var(const Var & var);
Var & operator=(const Var & var);
~Var();
// IMPROVEME add move cctor and operator=
Var * add_child(const std::wstring & child_name, const Var & var);
Var * find_child(const std::wstring & child_name);
bool has_object();
bool has_model_object();
void clear();
void clear_childs();
bool to_bool() const;
void set(const char * str);
void set(const wchar_t * str);
void set(const std::string & str);
void set(const std::wstring & str);
void set(bool val);
void set(short val);
void set(int val);
void set(long val);
void set(long long val);
void set(unsigned short val);
void set(unsigned int val);
void set(unsigned long val);
void set(unsigned long long val);
void set(float val);
void set(double val);
void set(long double val);
// this str object is copied
void set(const pt::Stream & str);
void set(UserFunction user_function);
void set(const pt::Date & date);
// this model is not copied, is it a correct interface?
void set(morm::Model & model);
void set(morm::ModelContainerWrapper & model_container_wrapper);
template<typename ModelType>
void set(std::vector<ModelType> & model_container);
template<typename ModelType>
void set(std::list<ModelType> & model_container);
template<typename ModelType>
void set(std::vector<ModelType*> & model_container);
template<typename ModelType>
void set(std::list<ModelType*> & model_container);
void set(morm::SpaceWrapper & space_wrapper);
void set(pt::Space & space, bool create_wrapper = true);
bool is_equal(const char * str) const;
bool is_equal(const wchar_t * str) const;
bool is_equal(const std::string & str) const;
bool is_equal(const std::wstring & str) const;
void serialize_to(pt::WTextStream & str);
Var & operator<<(const char * str);
Var & operator<<(const wchar_t * str);
Var & operator<<(const std::string & str);
Var & operator<<(const std::wstring & str);
Var & operator<<(char val);
Var & operator<<(unsigned char val);
Var & operator<<(wchar_t val);
Var & operator<<(bool val);
Var & operator<<(short val);
Var & operator<<(int val);
Var & operator<<(long val);
Var & operator<<(long long val);
Var & operator<<(unsigned short val);
Var & operator<<(unsigned int val);
Var & operator<<(unsigned long val);
Var & operator<<(unsigned long long val);
Var & operator<<(float val);
Var & operator<<(double val);
Var & operator<<(long double val);
Var & operator<<(const pt::Stream & str);
Type type;
UserFunction user_function;
morm::Model * model;
morm::ModelContainerWrapper * model_container_wrapper;
pt::Date * date;
morm::SpaceWrapper * space_wrapper;
pt::Space space_local;
StreamType stream;
pt::Space * space;
private:
std::map<std::wstring, Var> childs_map;
void initialize_empty();
void copy(const Var & var);
bool is_equal_bool(const char * str) const;
bool is_equal_string(const char * str) const;
bool is_equal_bool(const wchar_t * str) const;
bool is_equal_string(const wchar_t * str) const;
void assert_type_stream();
/*
* old
*/
/*
* if true then means 'str' is a function name and should be called (res is ignored)
*
* if false then means 'str' is a string value and res is a boolean value
*/
//bool is_function;
//std::wstring str; // a string value
//bool res; // a boolean value
};
template<typename StreamType>
Var<StreamType>::Var()
{
initialize_empty();
}
template<typename StreamType>
Var<StreamType>::Var(const Var & var)
{
initialize_empty();
copy(var);
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator=(const Var & var)
{
clear();
copy(var);
return *this;
}
template<typename StreamType>
void Var<StreamType>::copy(const Var & var)
{
type = var.type;
user_function = var.user_function;
model = var.model;
model_container_wrapper = var.model_container_wrapper;
date = var.date;
space_wrapper = var.space_wrapper;
space_local = var.space_local;
stream = var.stream;
space = var.space;
if( model_container_wrapper )
{
model_container_wrapper->increment_reference_counter();
}
if( space_wrapper )
{
space_wrapper->increment_reference_counter();
}
// childs_map don't need to be copied
}
template<typename StreamType>
Var<StreamType>::~Var()
{
clear();
}
template<typename StreamType>
void Var<StreamType>::initialize_empty()
{
type = TYPE_VOID;
user_function = nullptr;
model = nullptr;
model_container_wrapper = nullptr;
date = nullptr;
space_wrapper = nullptr;
space = nullptr;
}
template<typename StreamType>
void Var<StreamType>::clear()
{
if( model_container_wrapper )
{
model_container_wrapper->decrement_reference_counter();
if( model_container_wrapper->get_reference_counter() == 0 && model_container_wrapper->should_be_auto_removed() )
{
delete model_container_wrapper;
}
}
if( space_wrapper )
{
space_wrapper->decrement_reference_counter();
if( space_wrapper->get_reference_counter() == 0 && space_wrapper->should_be_auto_removed() )
{
delete space_wrapper;
}
}
initialize_empty();
space_local.clear();
stream.clear();
clear_childs();
}
template<typename StreamType>
void Var<StreamType>::clear_childs()
{
childs_map.clear();
}
template<typename StreamType>
Var<StreamType> * Var<StreamType>::add_child(const std::wstring & child_name, const Var & var)
{
Var & v = childs_map[child_name];
v.clear();
v = var;
return &v;
}
template<typename StreamType>
Var<StreamType> * Var<StreamType>::find_child(const std::wstring & child_name)
{
auto i = childs_map.find(child_name);
if( i != childs_map.end() )
{
return &i->second;
}
return nullptr;
}
template<typename StreamType>
bool Var<StreamType>::has_object()
{
return type != TYPE_VOID;
}
template<typename StreamType>
bool Var<StreamType>::has_model_object()
{
return model || model_container_wrapper;
}
template<typename StreamType>
bool Var<StreamType>::to_bool() const
{
switch(type)
{
case TYPE_VOID:
return false;
case TYPE_SPACE_LOCAL:
return space_local.to_bool();
case TYPE_STREAM:
return !stream.empty();
case TYPE_FUNCTION:
case TYPE_DATE:
case TYPE_MODEL:
break;
case TYPE_SPACE_WRAPPER:
return space_wrapper->get_space()->to_bool();
break;
case TYPE_SPACE:
return space->to_bool();
break;
case TYPE_MODEL_CONTAINER_WRAPPER:
return !model_container_wrapper->is_container_empty();
break;
}
return false;
}
template<typename StreamType>
void Var<StreamType>::set(const char * str)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(str);
}
template<typename StreamType>
void Var<StreamType>::set(const wchar_t * str)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(str);
}
template<typename StreamType>
void Var<StreamType>::set(const std::string & str)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(str);
}
template<typename StreamType>
void Var<StreamType>::set(const std::wstring & str)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(str);
}
template<typename StreamType>
void Var<StreamType>::set(bool val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(short val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(int val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(long val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(long long val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(unsigned short val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(unsigned int val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(unsigned long val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(unsigned long long val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(float val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(double val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(long double val)
{
clear();
type = TYPE_SPACE_LOCAL;
space_local.set(val);
}
template<typename StreamType>
void Var<StreamType>::set(const pt::Stream & str)
{
clear();
type = TYPE_STREAM;
stream.clear();
stream << str;
}
template<typename StreamType>
void Var<StreamType>::set(UserFunction user_function)
{
clear();
type = TYPE_FUNCTION;
this->user_function = user_function;
}
template<typename StreamType>
void Var<StreamType>::set(const pt::Date & date)
{
clear();
type = TYPE_DATE;
this->date = &date;
}
template<typename StreamType>
void Var<StreamType>::set(morm::Model & model)
{
clear();
type = TYPE_MODEL;
this->model = &model;
}
template<typename StreamType>
void Var<StreamType>::set(morm::ModelContainerWrapper & model_container_wrapper)
{
clear();
type = TYPE_MODEL_CONTAINER_WRAPPER;
this->model_container_wrapper = &model_container_wrapper;
this->model_container_wrapper->increment_reference_counter();
}
template<typename StreamType>
template<typename ModelType>
void Var<StreamType>::set(std::vector<ModelType> & model_container)
{
clear();
type = TYPE_MODEL_CONTAINER_WRAPPER;
this->model_container_wrapper = new morm::ModelWrapperVector<ModelType>(&model_container);
}
template<typename StreamType>
template<typename ModelType>
void Var<StreamType>::set(std::list<ModelType> & model_container)
{
clear();
type = TYPE_MODEL_CONTAINER_WRAPPER;
this->model_container_wrapper = new morm::ModelWrapperList<ModelType>(&model_container);
}
template<typename StreamType>
template<typename ModelType>
void Var<StreamType>::set(std::vector<ModelType*> & model_container)
{
clear();
type = TYPE_MODEL_CONTAINER_WRAPPER;
this->model_container_wrapper = new morm::ModelWrapperVectorPointer<ModelType>(&model_container);
}
template<typename StreamType>
template<typename ModelType>
void Var<StreamType>::set(std::list<ModelType*> & model_container)
{
clear();
type = TYPE_MODEL_CONTAINER_WRAPPER;
this->model_container_wrapper = new morm::ModelWrapperListPointer<ModelType>(&model_container);
}
template<typename StreamType>
void Var<StreamType>::set(morm::SpaceWrapper & space_wrapper)
{
clear();
type = TYPE_SPACE_WRAPPER;
this->space_wrapper = &space_wrapper;
this->space_wrapper->increment_reference_counter();
}
template<typename StreamType>
void Var<StreamType>::set(pt::Space & space, bool create_wrapper)
{
clear();
if( create_wrapper )
{
type = TYPE_SPACE_WRAPPER;
this->space_wrapper = new morm::SpaceWrapper(&space);
}
else
{
type = TYPE_SPACE;
this->space = &space;
}
}
template<typename StreamType>
bool Var<StreamType>::is_equal(const char * str) const
{
switch(type)
{
case TYPE_SPACE_LOCAL:
if( space_local.is_str() || space_local.is_wstr() )
return is_equal_string(str);
if( space_local.is_bool() )
return is_equal_bool(str);
// IMPLEMENTME
// implement the rest of conversion methods
return false;
case TYPE_VOID:
case TYPE_STREAM:
case TYPE_FUNCTION:
case TYPE_DATE:
case TYPE_MODEL:
case TYPE_MODEL_CONTAINER_WRAPPER:
case TYPE_SPACE_WRAPPER:
case TYPE_SPACE:
// IMPLEMENTME
break;
}
return false;
}
template<typename StreamType>
bool Var<StreamType>::is_equal(const wchar_t * str) const
{
switch(type)
{
case TYPE_SPACE_LOCAL:
if( space_local.is_str() || space_local.is_wstr() )
return is_equal_string(str);
if( space_local.is_bool() )
return is_equal_bool(str);
// IMPLEMENTME
// implement the rest of conversion methods
return false;
case TYPE_VOID:
case TYPE_STREAM:
case TYPE_FUNCTION:
case TYPE_DATE:
case TYPE_MODEL:
case TYPE_MODEL_CONTAINER_WRAPPER:
case TYPE_SPACE_WRAPPER:
case TYPE_SPACE:
// IMPLEMENTME
break;
}
return false;
}
template<typename StreamType>
bool Var<StreamType>::is_equal(const std::string & str) const
{
return is_equal(str.c_str());
}
template<typename StreamType>
bool Var<StreamType>::is_equal(const std::wstring & str) const
{
return is_equal(str.c_str());
}
template<typename StreamType>
bool Var<StreamType>::is_equal_bool(const char * str) const
{
if( space_local.to_bool() )
{
return str[0] != 0;
}
else
{
return str[0] == 0;
}
}
template<typename StreamType>
bool Var<StreamType>::is_equal_string(const char * str) const
{
if( space_local.is_str() )
{
return space_local.is_equal(str);
}
else
if( space_local.is_wstr() )
{
std::string space_str_utf8;
pt::wide_to_utf8(*space_local.get_wstr(), space_str_utf8);
return space_str_utf8 == str;
}
return false;
}
template<typename StreamType>
bool Var<StreamType>::is_equal_bool(const wchar_t * str) const
{
if( space_local.to_bool() )
{
return str[0] != 0;
}
else
{
return str[0] == 0;
}
}
template<typename StreamType>
bool Var<StreamType>::is_equal_string(const wchar_t * str) const
{
if( space_local.is_wstr() )
{
return space_local.is_equal(str);
}
else
if( space_local.is_str() )
{
std::string str_utf8;
pt::wide_to_utf8(str, str_utf8);
return space_local.is_equal(str_utf8);
}
return false;
}
template<typename StreamType>
void Var<StreamType>::serialize_to(pt::WTextStream & str)
{
switch(type)
{
case TYPE_SPACE_LOCAL:
space_local.serialize_to_string(str);
break;
case TYPE_STREAM:
str << stream;
break;
case TYPE_DATE:
date->SerializeISO(str);
break;
case TYPE_VOID:
case TYPE_FUNCTION:
break;
case TYPE_MODEL:
case TYPE_MODEL_CONTAINER_WRAPPER:
// 'model' is a forward declaration, we cannot call 'to_text' method
break;
case TYPE_SPACE_WRAPPER:
space_wrapper->get_space()->serialize_to_string(str);
break;
case TYPE_SPACE:
space->serialize_to_string(str);
break;
}
}
template<typename StreamType>
void Var<StreamType>::assert_type_stream()
{
if( type != TYPE_STREAM )
{
clear();
type = TYPE_STREAM;
}
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(const char * str)
{
assert_type_stream();
stream << str;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(const wchar_t * str)
{
assert_type_stream();
stream << str;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(const std::string & str)
{
assert_type_stream();
stream << str;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(const std::wstring & str)
{
assert_type_stream();
stream << str;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(char val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(unsigned char val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(wchar_t val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(bool val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(short val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(int val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(long val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(long long val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(unsigned short val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(unsigned int val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(unsigned long val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(unsigned long long val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(float val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(double val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(long double val)
{
assert_type_stream();
stream << val;
return *this;
}
template<typename StreamType>
Var<StreamType> & Var<StreamType>::operator<<(const pt::Stream & str)
{
assert_type_stream();
stream << str;
return *this;
}
}
#endif