/* * This file is a part of EZC -- Easy templating in C++ library * and is distributed under the BSD 3-Clause licence. * Author: Tomasz Sowa */ /* * 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 struct Env; /* a variable */ template class Var { public: typedef void (*UserFunction)(Env &); 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 void set(std::vector & model_container); template void set(std::list & model_container); template void set(std::vector & model_container); template void set(std::list & 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 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 Var::Var() { initialize_empty(); } template Var::Var(const Var & var) { initialize_empty(); copy(var); } template Var & Var::operator=(const Var & var) { clear(); copy(var); return *this; } template void Var::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 Var::~Var() { clear(); } template void Var::initialize_empty() { type = TYPE_VOID; user_function = nullptr; model = nullptr; model_container_wrapper = nullptr; date = nullptr; space_wrapper = nullptr; space = nullptr; } template void Var::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 void Var::clear_childs() { childs_map.clear(); } template Var * Var::add_child(const std::wstring & child_name, const Var & var) { Var & v = childs_map[child_name]; v.clear(); v = var; return &v; } template Var * Var::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 bool Var::has_object() { return type != TYPE_VOID; } template bool Var::has_model_object() { return model || model_container_wrapper; } template bool Var::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 void Var::set(const char * str) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(str); } template void Var::set(const wchar_t * str) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(str); } template void Var::set(const std::string & str) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(str); } template void Var::set(const std::wstring & str) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(str); } template void Var::set(bool val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(short val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(int val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(long val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(long long val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(unsigned short val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(unsigned int val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(unsigned long val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(unsigned long long val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(float val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(double val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(long double val) { clear(); type = TYPE_SPACE_LOCAL; space_local.set(val); } template void Var::set(const pt::Stream & str) { clear(); type = TYPE_STREAM; stream.clear(); stream << str; } template void Var::set(UserFunction user_function) { clear(); type = TYPE_FUNCTION; this->user_function = user_function; } template void Var::set(const pt::Date & date) { clear(); type = TYPE_DATE; this->date = &date; } template void Var::set(morm::Model & model) { clear(); type = TYPE_MODEL; this->model = &model; } template void Var::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 template void Var::set(std::vector & model_container) { clear(); type = TYPE_MODEL_CONTAINER_WRAPPER; this->model_container_wrapper = new morm::ModelWrapperVector(&model_container); } template template void Var::set(std::list & model_container) { clear(); type = TYPE_MODEL_CONTAINER_WRAPPER; this->model_container_wrapper = new morm::ModelWrapperList(&model_container); } template template void Var::set(std::vector & model_container) { clear(); type = TYPE_MODEL_CONTAINER_WRAPPER; this->model_container_wrapper = new morm::ModelWrapperVectorPointer(&model_container); } template template void Var::set(std::list & model_container) { clear(); type = TYPE_MODEL_CONTAINER_WRAPPER; this->model_container_wrapper = new morm::ModelWrapperListPointer(&model_container); } template void Var::set(morm::SpaceWrapper & space_wrapper) { clear(); type = TYPE_SPACE_WRAPPER; this->space_wrapper = &space_wrapper; this->space_wrapper->increment_reference_counter(); } template void Var::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 bool Var::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 bool Var::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 bool Var::is_equal(const std::string & str) const { return is_equal(str.c_str()); } template bool Var::is_equal(const std::wstring & str) const { return is_equal(str.c_str()); } template bool Var::is_equal_bool(const char * str) const { if( space_local.to_bool() ) { return str[0] != 0; } else { return str[0] == 0; } } template bool Var::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 bool Var::is_equal_bool(const wchar_t * str) const { if( space_local.to_bool() ) { return str[0] != 0; } else { return str[0] == 0; } } template bool Var::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 void Var::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 void Var::assert_type_stream() { if( type != TYPE_STREAM ) { clear(); type = TYPE_STREAM; } } template Var & Var::operator<<(const char * str) { assert_type_stream(); stream << str; return *this; } template Var & Var::operator<<(const wchar_t * str) { assert_type_stream(); stream << str; return *this; } template Var & Var::operator<<(const std::string & str) { assert_type_stream(); stream << str; return *this; } template Var & Var::operator<<(const std::wstring & str) { assert_type_stream(); stream << str; return *this; } template Var & Var::operator<<(char val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(unsigned char val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(wchar_t val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(bool val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(short val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(int val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(long val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(long long val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(unsigned short val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(unsigned int val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(unsigned long val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(unsigned long long val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(float val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(double val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(long double val) { assert_type_stream(); stream << val; return *this; } template Var & Var::operator<<(const pt::Stream & str) { assert_type_stream(); stream << str; return *this; } } #endif