/**
 * @package de.atwillys.cc.swl
 * @license BSD (simplified)
 * @author Stefan Wilhelm (stfwi)
 *
 * @file var.hh
 * @ccflags
 * @ldflags
 * @platform linux, bsd, windows
 * @standard >= c++98
 *
 * -----------------------------------------------------------------------------
 *
 * Simple "any-type" class template that works without runtime type information
 * (`-fno-rtti`).
 *
 * -----------------------------------------------------------------------------
 * +++ BSD license header +++
 * Copyright (c) 2010-2014, Stefan Wilhelm (stfwi, <cerbero s@atwilly s.de>)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met: (1) Redistributions
 * of source code must retain the above copyright notice, this list of conditions
 * and the following disclaimer. (2) 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.
 * (3) Neither the name of atwillys.de nor the names of its contributors 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 VAR 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 HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR VAR 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 VAR THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN VAR
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * -----------------------------------------------------------------------------
 */
#ifndef SW_ANY_HH
#define	SW_ANY_HH
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <cmath>
#include <limits>
#include <cstring>
#if !(defined(DEBUG)) || (DEBUG==0)
#define asrt(X)
#define dbg1(X)
#define dbg2(X)
#define dbg3(X)
#else
#include <cassert>
#define asrt(X) assert(X);
#define dbg1(X) std::cerr << X << std::endl
#if DEBUG > 1
#define dbg2(X) std::cerr << X << std::endl
#else
#define dbg2(X)
#endif
#if DEBUG > 2
#define dbg3(X) std::cerr << X << std::endl
#else
#define dbg3(X)
#endif
#endif

namespace sw { namespace detail {

/**
 * Class class basic_var<...>
 * - no-rtti compatible
 */
template <typename StringType, typename FloatType, typename IntType>
class basic_var
{
public:

  typedef StringType string_type;
  typedef FloatType float_type;
  typedef IntType int_type;
  typedef typename string_type::value_type char_t;
  typedef std::map<string_type, basic_var> map_t;
  typedef std::vector<basic_var> vect_t;
  typedef enum { tnull=0, tbool, tint, tfloat, tstr, tvect, tmap, tunset } type_t;

public:

  /**
   * Standard constructor
   */
  inline basic_var() : t_(tnull), d_()
  { ; }

  /**
   * Typespec constructor
   */
  explicit inline basic_var(type_t t) : t_(t), d_()
  { ; } // Note: Pointers for empty containers can be NULL.

  /**
   * Assignment constructor. Sets null type on caught exceptions.
   * @param const T& v
   */
  template<typename T>
  inline basic_var(const T& v) : t_(tnull), d_()
  { try { assign(v); } catch(...) { clear(); } }

  /**
   * Assignment constructor. Sets null type on caught exceptions.
   * @param const T& v
   */
  template<typename T>
  explicit inline basic_var(const T* v) : t_(tnull), d_()
  { try { assign(v); } catch(...) { clear(); } }

  /**
   * Standard operator=. Returns reference, not const reference.
   * @param const basic_var& v
   * @return basic_var&
   */
  inline basic_var& operator=(const basic_var& v)
  { assign(v); return *this; }

  /**
   * Destructor
   * Clears (containers recursively) before deallocating.
   */
  virtual ~basic_var()
  { clear(); }

  /**
   * Returns if the content is empty (value 0, no children, empty text)
   * @return bool
   */
  inline bool operator ! ()
  { return empty(); }

  /**
   * Returns if equal to another var. Applies to numeric types and string,
   * map and vector always return false.
   * @param const basic_var &b
   * @return bool
   */
  inline bool operator==(const basic_var &b) const
  {
    if((type() <= tint)   && (b.type() <= tint))   return i() == b.i();
    if((type() <= tfloat) && (b.type() <= tfloat)) return f() == b.f();
    if((type() == tstr)   && (b.type() == tstr))   return s() == b.s();
    return false; // Todo: Add map/vector element compare ???
  }

  /**
   * Returns if not equal to another var. T.i. !operator==
   * @param const basic_var &b
   * @return bool
   */
  inline bool operator!=(const basic_var &b) const
  { return !((*this)==b); }

  /**
   * Less-equal. Checked for numeric types and string, always false for map
   * and vector.
   * @param const basic_var &b
   * @return bool
   */
  inline bool operator<=(const basic_var &b) const
  {
    if(type()<=tint   && b.type()<=tint)   return i() <= b.i();
    if(type()<=tfloat && b.type()<=tfloat) return f() <= b.f();
    if(type()==tstr   && b.type()==tstr)   return s() <= b.s();
    return false;
  }

  /**
   * Greater-equal. Checked for numeric types and string, always false for map
   * and vector.
   * @param const basic_var &b
   * @return bool
   */
  inline bool operator>=(const basic_var &b) const
  {
    if(type()<=tint   && b.type()<=tint)   return i() >= b.i();
    if(type()<=tfloat && b.type()<=tfloat) return f() >= b.f();
    if(type()==tstr   && b.type()==tstr)   return s() >= b.s();
    return false;
  }

  /**
   * Less than. Checked for numeric types and string, always false for map
   * and vector.
   * @param const basic_var &b
   * @return bool
   */
  inline bool operator<(const basic_var &b) const
  {
    if(type()<=tint   && b.type()<=tint)   return i() < b.i();
    if(type()<=tfloat && b.type()<=tfloat) return f() < b.f();
    if(type()==tstr   && b.type()==tstr)   return s() < b.s();
    return false;
  }

  /**
   * Greater than. Checked for numeric types and string, always false for map
   * and vector.
   * @param const basic_var &b
   * @return bool
   */
  inline bool operator>(const basic_var &b) const
  {
    if(type()<=tint   && b.type()<=tint)   return i() > b.i();
    if(type()<=tfloat && b.type()<=tfloat) return f() > b.f();
    if(type()==tstr   && b.type()==tstr)   return s() > b.s();
    return false;
  }

public:

  //////////////////////////////////////////////////////////////////////////////
  // General information (methods const)

  /**
   * Returns the current type as enumeration value
   * @return type_t
   */
  inline type_t type() const throw()
  { return t_; }

  /**
   * Returns the type name as string
   * @return const char_t*
   */
  inline const char_t * typen() const throw()
  { static const char_t* tnames[] = { "null", "bool", "int", "float", "string",
    "vector", "map", "(unknown)" }; return t_>=0 && t_<tunset ?
    tnames[(unsigned)t_] : tnames[(unsigned)tunset]; }

  /**
   * Returns true if the current data type is null
   * @return bool
   */
  inline bool is_null() const throw()
  { return t_ == tnull; }

  /**
   * Returns true if the current data type is int
   * @return bool
   */
  inline bool is_int() const throw()
  { return t_ == tint; }

  /**
   * Returns true if the current data type is bool
   * @return bool
   */
  inline bool is_bool() const throw()
  { return t_ == tbool; }

  /**
   * Returns true if the current data type is float_type
   * @return bool
   */
  inline bool is_float() const throw()
  { return t_ == tfloat; }

  /**
   * Returns true if the current data type is string_type
   * @return bool
   */
  inline bool is_string() const throw()
  { return t_ == tstr; }

  /**
   * Returns true if the current data type is vector
   * @return bool
   */
  inline bool is_vector() const throw()
  { return t_ == tvect; }

  /**
   * Returns true if the current data type is map
   * @return bool
   */
  inline bool is_map() const throw()
  { return t_ == tmap; }

  /**
   * True if the data type is `unset`
   * @return bool
   */
  inline bool is_unset() const throw()
  { return t_<0 || t_ >= tunset; }

  /**
   * Returns of the value is 0 or the container empty.
   * @return bool
   */
  inline bool empty() const throw()
  { return d_.d==0 || t_<=tnull || t_>=tunset
      || (t_==tstr  && ((!d_.s) || d_.s->empty()))
      || (t_==tvect && ((!d_.v) || d_.v->empty()))
      || (t_==tmap  && ((!d_.m) || d_.m->empty()));
  }

  /**
   * Returns the size of the container/length of string or -1 if scalar/erroneous.
   * @return int
   */
  inline int size() const throw()
  { return (t_< tstr || t_>tmap || (!d_.s)) ? (-1)
         : (t_==tstr  ? d_.s->length()
         : (t_==tvect ? d_.v->size()
         : (t_==tmap  ? d_.m->size()
         : (-1) )));
  }

public:

  //////////////////////////////////////////////////////////////////////////////
  // General modification

  /**
   * Clearing: Numeric/bool value=0, pointer=NULL, optionally delete container.
   * After clearing the type is `unset`.
   * @return void
   */
  inline void clear()
  {
    if(t_ >= tstr && t_<= tmap && d_.s) {
      t_ = tnull;
      switch(t_) {
        case tstr: delete  d_.s; break;
        case tvect: delete d_.v; break;
        case tmap: delete  d_.m; break;
        default: ; // throw ?
      }
    }
    ::memset(&d_, 0, sizeof(union data_t));
    t_ = tunset;
  }

  /**
   * Filters out undefined basic_var elements in the vector/map.
   * @return basic_var & *this
   */
  basic_var & erase_undefs()
  {
    if(t_==tvect && (d_.v)) {
      vect_t& rv = *d_.v;
      if(!rv.empty()) {
        int i = (int)(rv.size()-1);
        while(rv[i].is_unset()) --i;
        if(i<0) { v(empty_vector()); return *this; }
        rv.resize(i+1);
        while(i>=0) {
          if(rv[i].is_unset()) rv.erase(rv.begin()+i);
          else rv[i].erase_undefs();
          --i;
        }
        if(rv.empty()) v(empty_vector()); // Reallocate
      }
      return *this;
    }
    if(t_ == tmap && (d_.m)) {
      map_t& rm = *d_.m;
      for(typename map_t::iterator it=rm.begin(); it!=rm.end(); ++it) {
        if(it->second.is_unset()) {
          rm.erase(it); // stfwi: double check if iterator still points to the correct next after erasing
        } else {
          it->second.erase_undefs();
        }
      }
    }
    return *this;
  }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Specific type getters

  /**
   * Return integer value or 0 if inappropriate
   * @return int_type
   */
  inline int_type i() const
  { return t_ <= tint ? d_.i : (t_==tfloat ? sat_cast<float_type, int_type>(d_.d) : 0); }

  /**
   * Return integer value or 0 if inappropriate
   * @return int_type
   */
  inline bool b() const
  { return i() != 0; }

  /**
   * Return floating point value or NaN if inappropriate
   * @return float_type
   */
  inline float_type f() const
  { return t_ <= tint ? (float_type)d_.i : (t_==tfloat ? d_.d : std::numeric_limits<double>::quiet_NaN()); }

  /**
   * String value, no type conversion, empty if inappropriate
   * @return const string_type &
   */
  inline const string_type & s() const
  { return (t_==tstr && d_.s!=0) ? *d_.s : empty_string(); }

  /**
   * Vector value, no type conversion, empty if inappropriate
   * @return const vect_t &
   */
  inline const vect_t & v() const
  { return (t_==tvect && d_.v!=0) ? *d_.v : empty_vector(); }

  /**
   * Map value, no type conversion, empty if inappropriate
   * @return const map_t &
   */
  inline const map_t & m() const
  { return (t_==tmap && d_.m!=0) ? *d_.m : empty_map(); }


public:

  //////////////////////////////////////////////////////////////////////////////
  // Specific type setters

  /**
   * Assign integer value
   * @return float_type
   */
  inline basic_var& i(int_type v)
  { if(t_ >= tstr) clear(); t_ = tint; d_.i = v; return *this; }

  /**
   * Assign integer value
   * @return float_type
   */
  inline basic_var& b(bool v)
  { if(t_ >= tstr) clear(); t_ = tbool; d_.i = (int_type) v; return *this; }

  /**
   * Assign floating point value
   * @float_type v
   * @return basic_var&
   */
  inline basic_var& f(float_type v)
  { if(t_ >= tstr) clear(); t_ = tfloat; d_.d = v; return *this; }

  /**
   * Assign string value (copy)
   * @param const string_type &
   * @return basic_var&
   */
  inline basic_var& s(const string_type & s)
  {
    if(t_ > tstr) clear();
    if(t_ != tstr || !d_.s) {
      try { d_.s = new string_type(s); } catch(...) { d_.s = 0; }
      t_ = !d_.s ? tunset : tstr;
    } else {
      d_.s->assign(s);
    }
    return *this;
  }

  /**
   * Assign vector value (copy)
   * @param const vect_t &
   * @return basic_var&
   */
  inline basic_var& v(const vect_t & v__)
  { if(t_ >= tstr) clear(); d_.v = new vect_t(v__); t_ = ((!d_.v) ? tunset : tvect);
    return *this; }

  /**
   * Assign map value (copy)
   * @param const map_t &
   * @return basic_var&
   */
  inline basic_var& m(const map_t & m__)
  { if(t_ >= tstr) clear(); d_.m = new map_t(m__); t_ = !d_.m ? tunset : tmap;
    return *this; }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Vector specific

  /**
   * Vector value by index
   * @return const basic_var &
   */
  inline const basic_var & v(int i) const
  { return (t_!=tvect || (!d_.v) || i<0 || i>=(int)d_.v->size()) ?
      undef() : (d_.v->at(i)); }

  /**
   * Writable vector value by index. If the current type is null or `unset`,
   * it will be changed to vector. If the index does not exist returns a reference
   * to the undef() object.
   * @return basic_var &
   */
  inline basic_var & v(int i)
  {
    if(t_==tnull || t_==tunset) { clear(); v(empty_vector()); }
    if(t_!=tvect || (!d_.v) || i<0 || i>=(int)d_.v->size()) return undef_ref();
    return d_.v->at(i);
  }

  /**
   * Vector value by index
   * @param const int &i
   * @return const basic_var &
   */
  inline const basic_var & operator[] (int i) const
  { return v(i); }

  /**
   * Vector value by index
   * @param const int &i
   * @return basic_var &
   */
  inline basic_var & operator[] (int i)
  { return v(i); }

  /**
   * Vector: Return first element or `unset` if empty
   * Other : Return const `unset`
   * @return basic_var &
   */
  inline const basic_var & front() const
  { return (t_!=tvect || (!d_.v) || d_.v->empty()) ? undef() : d_.v->front() ; }

  /**
   * Vector: Return first element or `unset` if empty
   * Other : Return const `unset`
   * @return basic_var &
   */
  inline const basic_var & back() const
  { return (t_!=tvect || (!d_.v) || d_.v->empty()) ? undef() : d_.v->back() ; }

  /**
   * Vector: Append value at the end
   * Other : Do nothing
   * @return basic_var & *this;
   */
  inline basic_var & push_back (const basic_var & o)
  {
    if(o.is_unset()) return *this;
    if(t_==tnull || t_==tunset) v(empty_vector());
    if(t_!=tvect) return *this;
    d_.v->push_back(o);
    return *this;
  }

  /**
   * Vector: Append value at the front
   * Other : Do nothing
   * @return basic_var & *this;
   */
  inline basic_var & push_front (const basic_var & o)
  {
    if(o.is_unset()) return *this;
    if(t_==tnull || t_==tunset) v(empty_vector());
    if(t_!=tvect) return *this;
    d_.v->insert(d_.v->begin(), o);
    return *this;
  }

  /**
   * Erase vector element before position `i`
   * @param int i
   * @const basic_var &v
   * @return basic_var & *this
   */
  inline basic_var & insert(int i, const basic_var &o)
  {
    if(o.is_unset()) return *this;
    if(t_==tnull || t_==tunset) v(empty_vector());
    if(t_!=tvect) return *this;
    if(d_.v->empty() || (i>=(int)d_.v->size())) d_.v->push_back(o);
    else d_.v->insert(d_.v->begin()+(i<0 ? 0 : i), o);
    return *this;
  }

  /**
   * Vector: Remove first element.
   * Other : Do nothing
   * @return basic_var & *this
   */
  inline basic_var & pop_front()
  {
    if(t_==tvect && (d_.v!=0) && (!d_.v->empty())) {
      if(d_.v->size()==1) v(empty_vector());
      else d_.v->erase(d_.v->begin());
    }
    return *this;
  }

  /**
   * Vector: Remove last element.
   * Other : Do nothing
   * @return basic_var & *this
   */
  inline basic_var & pop_back()
  {
    if(t_==tvect && (d_.v!=0) && !(d_.v->empty())) {
      if(d_.v->size()==1) v(empty_vector()); // not d_.v->clear();
      else d_.v->pop_back();
    }
    return *this;
  }

  /**
   * Erase vector element at position `i`
   * @param int i
   * @return basic_var & *this
   */
  inline basic_var & erase(int i)
  {
    if(t_==tvect && (d_.v) && i>=0 && i<(int)d_.v->size()) {
      if(i==0 && d_.v->size()==1) v(empty_vector()); // not d_.v->clear();
      else d_.v->erase(d_.v->begin()+(typename vect_t::size_type)i);
    }
    return *this;
  }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Map specific

  /**
   * Map value by key
   * @param const string_type &key
   * @return const basic_var &
   */
  inline const basic_var & m(const string_type& key) const
  {
    if (t_!=tmap || (!d_.m)) return undef();
    typename map_t::const_iterator it = d_.m->find(key);
    return it == d_.m->end() ? undef() : it->second;
  }

  /**
   * Map value by key
   * @param const string_type &key
   * @return basic_var &
   */
  inline basic_var & m(const string_type& key)
  {
    if(key.empty()) return undef_ref();
    if(t_==tunset || t_==tnull) m(empty_map());
    if(t_!=tmap || (!d_.m)) return undef_ref();
    typename map_t::iterator it = d_.m->find(key);
    if(it == d_.m->end()) {
      std::pair<typename map_t::iterator, bool> r =
        d_.m->insert(std::pair<string_type, basic_var>(key, undef()));
      if(r.first == d_.m->end() || !r.second) {
        clear();
        return undef_ref();
      } else {
        it = r.first;
      }
    }
    return it->second;
  }

  /**
   * Set map value
   * @param const string_type &key
   * @return basic_var & *this
   */
  inline basic_var & m(const string_type& key, const basic_var &v)
  { if(!key.empty() && !v.is_unset()) m(key) = v; return *this; }

  /**
   * Map value by key
   * @param const string_type &key
   * @return const basic_var &
   */
  inline const basic_var & operator[] (const string_type& key) const
  { return m(key); }

  /**
   * Map value by key
   * @param const char_t *key
   * @return const basic_var &
   */
  inline const basic_var & operator[] (const char_t *key) const
  { return key ? m(string_type(key)) : undef(); }

  /**
   * Map value by key
   * @param const string_type &key
   * @return basic_var &
   */
  inline basic_var & operator[] (const string_type& key)
  { return m(key); }

  /**
   * Map value by key
   * @param const char_t *key
   * @return basic_var &
   */
  inline basic_var & operator[] (const char_t *key)
  { return key ? m(string_type(key)) : undef_ref(); }

  /**
   * Erase map element with key `key`
   * @param const string_type &key
   * @return basic_var & *this
   */
  inline basic_var & erase(const string_type &key)
  {
    if(t_!=tmap || (!d_.m) || key.empty() || d_.m->empty()) return *this;
    if(d_.m->find(key) != d_.m->end()) d_.m->erase(key);
    return *this;
  }

  /**
   * Erase map element with key `key`
   * @param const char_t* key
   * @return basic_var & *this
   */
  inline basic_var & erase(const char_t* key)
  { if(key) erase(string_type(key)); return *this; }

  //////////////////////////////////////////////////////////////////////////////
  // String specific

  /**
   * String value, implicit conversion, empty if inappropriate
   * @return string_type
   */
  string_type str() const
  {
    ss_t ss; // let stringstream handle char/wchar string conversion
    switch(t_) {
      case tnull: return "null";
      case tbool: return d_.i ? "true" : "false";
      case tint: ss << d_.i; break;
      case tfloat: ss << d_.d; break;
      case tstr: return d_.s ? (*d_.s) : "invalid string";
      case tvect:
        if(!d_.v) return "invalid vector";
        ss << "vector(" << (int) d_.v->size() << ")";
        break;
      case tmap:
        if(!d_.m) return "invalid map";
        ss << "map(" << ((int) d_.m->size()) << ")";
        break;
      case tunset:
        return "undef";
      default:
        return "invalid type";
    }
    return ss.str();
  }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Clause operators

  inline bool operator==(const string_type &b) const
  {
    if(type() == tstr) return s() == b;
    if(type() > tstr) return false;
    if(empty()) return b.empty();
    if(b.empty()) return empty();
    std::stringstream ss((string_type)b);
    double d; return (!(ss>>d)) ? false : (f() == d);
  }

  inline bool operator!=(const string_type &b) const
  { return !operator==(b); }

  inline bool operator<(const string_type &b) const
  {
    if(type() == tstr) return s() < b;
    if(type() > tstr) return false;
    if(empty()) return !b.empty();
    if(b.empty()) return false;
    std::stringstream ss((string_type)b);
    double d; return (!(ss>>d)) ? false : (f() < d);
  }

  inline bool operator>(const string_type &b) const
  {
    if(type() > tstr) return false;
    if(empty()) return false;
    if(type() == tstr) return s() > b;
    if(b.empty()) return true;
    std::stringstream ss((string_type)b);
    double d; return (!(ss>>d)) ? false : (f() > d);
  }

  inline bool operator>=(const string_type &b) const
  {
    if(type() == tstr) return s() >= b;
    if(type() > tstr) return false;
    if(empty()) return b.empty();
    std::stringstream ss((string_type)b);
    double d; return (!(ss>>d)) ? false : (f() >= d);
  }

  inline bool operator<=(const string_type &b) const
  {
    if(type() == tstr) return s() <= b;
    if(type() > tstr) return false;
    if(b.empty()) return empty();
    std::stringstream ss((string_type)b);
    double d; return (!(ss>>d)) ? false : (f() <= d);
  }

  inline bool operator==(const char_t *b) const
  { return (!b) ? empty() : operator==(string_type(b)); }

  inline bool operator!=(const char_t *b) const
  { return !operator==(b); }

  inline bool operator>(const char_t *b) const
  { return (!b) ? !empty() : operator>(string_type(b)); }

  inline bool operator<(const char_t *b) const
  { return (!b) ? false : operator<(string_type(b)); }

  inline bool operator<=(const char_t *b) const
  { return (!b) ? empty() : operator<=(string_type(b)); }

  inline bool operator>=(const char_t *b) const
  { return (!b) ? true : operator>=(string_type(b)); }

  #define operator_primitives(T) \
  inline bool operator==(const T &b) const { return ((T)(*this)) == b; } \
  inline bool operator!=(const T &b) const { return ((T)(*this)) != b; } \
  inline bool operator>=(const T &b) const { return ((T)(*this)) >= b; } \
  inline bool operator<=(const T &b) const { return ((T)(*this)) <= b; } \
  inline bool operator> (const T &b) const { return ((T)(*this)) >  b; } \
  inline bool operator< (const T &b) const { return ((T)(*this)) <  b; }
  operator_primitives(bool)
  operator_primitives(char)
  operator_primitives(unsigned char)
  operator_primitives(short)
  operator_primitives(unsigned short)
  operator_primitives(int)
  operator_primitives(unsigned int)
  operator_primitives(long)
  operator_primitives(unsigned long)
  operator_primitives(float)
  operator_primitives(double)
  #undef operator_primitives

public:

  //////////////////////////////////////////////////////////////////////////////
  // Typecast operators

  /**
   * Equivalent to b()
   * @return bool
   */
  inline operator bool () const
  { return b(); }

  /**
   * Equivalent to f()
   * @return float
   */
  inline operator float () const
  { return (float) f(); }

  /**
   * Equivalent to f()
   * @return double
   */
  inline operator double () const
  { return f(); }

  /**
   * To string
   * @return string_type
   */
  inline operator string_type () const
  { return t_==tstr && d_.s ? s() : str(); }

  /**
   * Saturated type conversion
   * @return unsigned short
   */
  inline operator char () const
  {
    if(t_==tstr) return (d_.s && !d_.s->empty()) ? d_.s->at(0) : 0;
    return t_==tfloat ? sat_cast<float_type, char>(d_.d) : sat_cast<int_type, char>(i());
  }

  /**
   * Saturated type conversion
   * @return unsigned short
   */
  inline operator unsigned char () const
  { return t_==tfloat ? sat_cast<float_type, unsigned char>(d_.d) :
        sat_cast<int_type, unsigned char>(i()); }

  /**
   * Saturated type conversion
   * @return short
   */
  inline operator short () const
  { return t_==tfloat ? sat_cast<float_type, short>(d_.d) : sat_cast<int_type, short>(i()); }

  /**
   * Saturated type conversion
   * @return unsigned short
   */
  inline operator unsigned short () const
  { return t_==tfloat ? sat_cast<float_type, unsigned short>(d_.d) :
        sat_cast<int_type, unsigned short>(i()); }

  /**
   * Saturated type conversion
   * @return int
   */
  inline operator int () const
  { return t_==tfloat ? sat_cast<float_type, int>(d_.d) : sat_cast<int_type, int>(i()); }

  /**
   * Saturated type conversion
   * @return unsigned
   */
  inline operator unsigned () const
  { return t_==tfloat ? sat_cast<float_type, unsigned>(d_.d) : sat_cast<int_type, unsigned>(i()); }

  /**
   * Saturated type conversion
   * @return long
   */
  inline operator long () const
  { return t_==tfloat ? sat_cast<float_type, long>(d_.d) : sat_cast<int_type, long>(i()); }

  /**
   * Saturated type conversion
   * @return unsigned long
   */
  inline operator unsigned long () const
  { return t_==tfloat ? sat_cast<float_type, unsigned long>(d_.d) :
        sat_cast<int_type, unsigned long>(i()); }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Assignment

  /**
   * Allows easier assignment for primitive types. Specialisations of
   * assign() will be applied.
   * @param const T& v
   * @return basic_var& *this;
   */
  template <typename T> inline basic_var& operator=(const T& v)
  { assign(v); return *this; }

  /**
   * Allows easier assignment for primitive types. Specialisations of
   * assign() will be applied.
   * @param const T& v
   * @return basic_var& *this;
   */
  template <typename T> inline basic_var& operator=(const T* v)
  { assign(v); return *this; }

protected:

  //////////////////////////////////////////////////////////////////////////////
  // Assignment

  /**
   * @param const basic_var &o
   */
  inline void assign(const basic_var &o)
  {
    if(t_ >= tstr && d_.s) clear();
    if(o.type() == tnull)  { t_=tnull; d_.d=0; return; }
    if(o.type() <= tint)   { i(o.i()); return; }
    if(o.type() == tfloat) { f(o.f()); return; }
    if(o.type() == tstr)   { s(o.s()); return; }
    if(o.type() == tvect)  { v(o.v()); return; }
    if(o.type() == tmap)   { m(o.m()); return; }
    t_ = tunset;
  }

  inline void assign(const unsigned long &v)
  { if(v <= (unsigned long) std::numeric_limits<int_type>::max()) i(v); else f(v); }

  inline void assign(const long &v)
  { if(v > (long) std::numeric_limits<int_type>::max()
    || v < (long) std::numeric_limits<int_type>::min()) f(v); else i(v); }

  inline void assign(const unsigned int &v)
  { if(v <= (unsigned long) std::numeric_limits<int_type>::max()) i(v); else f(v); }

  inline void assign(const int &v)
  {
    if((v > (long) std::numeric_limits<int_type>::max())
    || (v < (long) std::numeric_limits<int_type>::min())) f(v); else i(v); }

  inline void assign(const string_type &v)
  { s(v); }

  inline void assign(const char_t &v)
  { s(string_type(1, v)); }

  inline void assign(const char_t *v)
  { if(v) s(v); else { clear(); t_=tunset; } }

  inline void assign(const vect_t &v__)
  { v(v__); }

  inline void assign(const map_t &v)
  { m(v); }

  inline void assign(const bool &v)
  { b(v); }

  inline void assign(const unsigned char &v)
  { i((int_type)v); }

  inline void assign(const short &v)
  { i((int_type)v); }

  inline void assign(const unsigned short &v)
  { i((int_type)v); }

  inline void assign(const float &v)
  { f(v); }

  inline void assign(const double &v)
  { f(v); }

  inline void assign(const volatile unsigned long &v)
  { assign((unsigned long)v); }

  inline void assign(const volatile long &v)
  { assign((long)v); }

  inline void assign(const volatile unsigned int &v)
  { assign((unsigned int)v); }

  inline void assign(const volatile int &v)
  { assign((int)v); }

  inline void assign(const volatile bool &v)
  { assign((bool)v); }

  inline void assign(const volatile unsigned char &v)
  { assign((unsigned char)v); }

  inline void assign(const volatile short &v)
  { assign((short)v); }

  inline void assign(const volatile unsigned short &v)
  { assign((unsigned short)v); }

  inline void assign(const volatile float &v)
  {  assign((float)v); }

  inline void assign(const volatile double &v)
  {  assign((double)v); }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Static object getters

  /**
   * Returns a basic_var that represents `null`
   * @return const basic_var &
   */
  inline static const basic_var & nul()
  { static const basic_var v(tnull); return v; }

  /**
   * Returns a basic_var const reference that is `unset`
   * @return const basic_var &
   */
  inline static const basic_var & undef()
  { static const basic_var v(tunset); return v; }

  /**
   * Returns a basic_var reference that is `unset`
   * @return basic_var &
   */
  inline static basic_var & undef_ref()
  { static basic_var v; v.d_.d=0; v.t_=tunset; return v; }

  /**
   * Returns a basic_var reference that is `unset`
   * @return const map_t &
   */
  inline static const map_t & empty_map()
  { static const map_t v; return v; }

  /**
   * Returns a reference to a constant empty vector.
   * @return const vect_t &
   */
  inline static const vect_t & empty_vector()
  { static const vect_t v; return v; }

  /**
   * Returns a reference to a constant empty string
   * @return const string_type &
   */
  inline static const string_type & empty_string()
  { static const string_type v; return v; }

public:

  //////////////////////////////////////////////////////////////////////////////
  // Dump

  void dump(std::basic_ostream<char_t>&os, int indent=0) const
  { if(indent<0) indent = 0; os << string_type(indent, ' '); dumpr(os, indent); }

protected:

  void dumpr(std::basic_ostream<char_t>&os, int indent) const
  {
    os << str();
    if(t_ == tvect) {
      if(!empty()) {
        os << " =" << std::endl << string_type(indent, ' ') << "[" << std::endl;
        for(int i=0; i<size(); ++i) {
          os << string_type(indent+2, ' ') << i << ": ";
          v(i).dumpr(os, indent+2);
        }
        os << string_type(indent, ' ') << "]";
      } else {
        os << "[]";
      }
    } else if(t_ == tmap) {
      if(!empty()) {
        os << " =" << std::endl << string_type(indent, ' ') << "{" << std::endl;
        typename map_t::const_iterator it = m().begin();
        typename map_t::const_iterator e = m().end();
        for(; it!=e; ++it) {
          os << string_type(indent+2, ' ') << "\"" << it->first << "\": ";
          it->second.dumpr(os, indent+2);
        }
        os << string_type(indent, ' ') << "}";
      } else {
        os << "{}";
      }
    }
    os << std::endl;
  }

  //////////////////////////////////////////////////////////////////////////////
  // Auxiliary functions / methods

  /**
   * Inlined numeric saturated cast
   * @param I v
   * @return O
   */
  template<typename I, typename O> inline static O sat_cast(I v)
  { // A lot of clauses that will be optimised away by the compiler
    #ifdef __MSC_VER
    #pragma warning(push)
    #pragma warning(disable: 4244)
    #endif
    #define i std::numeric_limits<I>
    #define o std::numeric_limits<O>
    if(i::is_integer && o::is_integer) {
      if((sizeof(O) >= sizeof(I)) && (i::is_signed == o::is_signed)) return (O) v;
      if(i::is_signed && !o::is_signed) return (I)v<0 ? (O)0 : (sizeof(O)>=sizeof(I)
           ? (O)v : ( v > (I)o::max() ? o::max() : v));
      if(!i::is_signed && o::is_signed) return (v > (I)o::max()) ? o::max() : (O)v;
      return v < (I)o::min() ? (I)o::min() : (v > (I)o::max() ? (I)o::max() : v);
    }
    if(!o::is_integer) return (O) v;
    return v < (I)o::min() ? (I)o::min() : (v > (I)o::max() ? (I)o::max() : v);
    #undef i
    #undef o
    #ifdef __MSC_VER
    #pragma warning(pop)
    #endif
  }

private:

  //////////////////////////////////////////////////////////////////////////////
  // Instance variables / private types

  typedef std::basic_stringstream<typename string_type::value_type> ss_t;
  type_t t_;

  union data_t {
    int_type i; float_type d; string_type* s; map_t* m; vect_t* v;
    data_t() { memset(this, 0, sizeof(*this)); }
  } d_;

};

////////////////////////////////////////////////////////////////////////////////
// ostream <<

/**
 * ostream <<
 * @param std::basic_ostream<typename string_type::value_type> &os
 * @param basic_var<string_type, float_type, int_type>
 * @return std::basic_ostream<typename string_type::value_type>&
 */
template <typename string_type, typename float_type, typename int_type>
std::basic_ostream<typename string_type::value_type>& operator << (
  std::basic_ostream<typename string_type::value_type>& os,
  const basic_var<string_type, float_type, int_type> &o
)
{
  os << o.str(); return os;
}

////////////////////////////////////////////////////////////////////////////////
// OPERATORS FOR sw::var    PRIMITIVE OP VAR

#define VAR basic_var<std::string, double, long>
inline bool operator==(const VAR::string_type &b, const VAR &a)  { return a == b; }
inline bool operator!=(const VAR::string_type &b, const VAR &a)  { return a != b; }
inline bool operator==(const VAR::char_t *b, const VAR &a) { return a == b; }
inline bool operator!=(const VAR::char_t *b, const VAR &a) { return a != b; }
#define operator_primitives(T) \
inline bool operator==(const T &b, const VAR &a) { return a == b; } \
inline bool operator!=(const T &b, const VAR &a) { return a != b; } \
inline bool operator>=(const T &b, const VAR &a) { return a <  b; } \
inline bool operator<=(const T &b, const VAR &a) { return a >  b; } \
inline bool operator> (const T &b, const VAR &a) { return a <= b; } \
inline bool operator< (const T &b, const VAR &a) { return a >= b; }
operator_primitives(bool)
operator_primitives(char)
operator_primitives(unsigned char)
operator_primitives(short)
operator_primitives(unsigned short)
operator_primitives(int)
operator_primitives(unsigned int)
operator_primitives(long)
operator_primitives(unsigned long)
operator_primitives(float)
operator_primitives(double)
#undef operator_primitives
#undef VAR
}}

////////////////////////////////////////////////////////////////////////////////

namespace sw {
  typedef detail::basic_var<std::string, double, long> var;
}

#endif
