<commit_before>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/rt/DynamicObject.h"

#include "db/rt/DynamicObjectIterator.h"
#include "db/rt/DynamicObjectIterators.h"

#include <cstdlib>
#include <cctype>

using namespace db::rt;

DynamicObject::DynamicObject() :
   Collectable<DynamicObjectImpl>(new DynamicObjectImpl())
{
}

DynamicObject::DynamicObject(DynamicObjectImpl* impl) :
   Collectable<DynamicObjectImpl>(impl)
{
}

DynamicObject::DynamicObject(const DynamicObject& rhs) :
   Collectable<DynamicObjectImpl>(rhs)
{
}

DynamicObject::~DynamicObject()
{
}

bool DynamicObject::operator==(const DynamicObject& rhs) const
{
   bool rval;

   const DynamicObject& lhs = *this;
   rval = Collectable<DynamicObjectImpl>::operator==(rhs);
   if(!rval && !lhs.isNull() && !rhs.isNull())
   {
      // compare heap objects
      rval = (*lhs == *rhs);
   }

   return rval;
}

bool DynamicObject::operator!=(const DynamicObject& rhs) const
{
   return !(*this == rhs);
}

bool DynamicObject::operator<(const DynamicObject& rhs) const
{
   bool rval;

   const DynamicObject& lhs = *this;

   // NULL is always less than anything other than NULL
   if(lhs.isNull())
   {
      rval = !rhs.isNull();
   }
   // lhs is not NULL, but rhs is, so rhs is not less
   else if(rhs.isNull())
   {
      rval = false;
   }
   // neither lhs or rhs is NULL, compare heap objects
   else
   {
      rval = (*lhs < *rhs);
   }

   return rval;
}

void DynamicObject::operator=(const char* value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(const unsigned char* value)
{
   operator=((const char*)value);
}

void DynamicObject::operator=(bool value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(int32_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(uint32_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(int64_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(uint64_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(double value)
{
   *mReference->ptr = value;
}

DynamicObject& DynamicObject::operator[](const char* name)
{
   return (*mReference->ptr)[name];
}

DynamicObject& DynamicObject::operator[](const unsigned char* name)
{
   return operator[]((const char*)name);
}

DynamicObject& DynamicObject::operator[](int index)
{
   return (*mReference->ptr)[index];
}

DynamicObjectIterator DynamicObject::getIterator() const
{
   DynamicObjectIteratorImpl* i;

   switch((*this)->getType())
   {
      case Map:
         i = new DynamicObjectIteratorMap((DynamicObject&)*this);
         break;
      case Array:
         i = new DynamicObjectIteratorArray((DynamicObject&)*this);
         break;
      default:
         i = new DynamicObjectIteratorSingle((DynamicObject&)*this);
         break;
   }

   return DynamicObjectIterator(i);
}

DynamicObject DynamicObject::first() const
{
   DynamicObject rval(NULL);

   // return first result of iterator
   DynamicObjectIterator i = getIterator();
   if(i->hasNext())
   {
      rval = i->next();
   }

   return rval;
}

DynamicObject DynamicObject::clone()
{
   DynamicObject rval;

   if(isNull())
   {
      rval.setNull();
   }
   else
   {
      int index = 0;
      rval->setType((*this)->getType());
      DynamicObjectIterator i = getIterator();
      while(i->hasNext())
      {
         DynamicObject dyno = i->next();
         switch((*this)->getType())
         {
            case String:
               rval = dyno->getString();
               break;
            case Boolean:
               rval = dyno->getBoolean();
               break;
            case Int32:
               rval = dyno->getInt32();
               break;
            case UInt32:
               rval = dyno->getUInt32();
               break;
            case Int64:
               rval = dyno->getInt64();
               break;
            case UInt64:
               rval = dyno->getUInt64();
               break;
            case Double:
               rval = dyno->getDouble();
               break;
            case Map:
               rval[i->getName()] = dyno.clone();
               break;
            case Array:
               rval[index++] = dyno.clone();
               break;
         }
      }
   }

   return rval;
}

bool DynamicObject::diff(
   DynamicObject& target, DynamicObject& result, uint32_t flags)
{
   bool rval = false;
   DynamicObject& source = (DynamicObject&)*this;
   // clear any old values
   result->clear();

   if(source.isNull() && target.isNull())
   {
      // same: no diff
   }
   else if(!source.isNull() && target.isNull())
   {
      // <stuff> -> NULL: diff=NULL
      rval = true;
      result = "[DiffError: target object is NULL]";
   }
   else if(source.isNull() && !target.isNull())
   {
      // NULL -> <stuff> -or- types differ: diff=target
      rval = true;
      result = "[DiffError: source object is NULL]";
   }
   else
   {
      // not null && same type: diff=deep compare
      switch(source->getType())
      {
         case Int32:
         case Int64:
         case UInt32:
         case UInt64:
            if(source->getType() != target->getType())
            {
               switch(target->getType())
               {
                  case Int32:
                  case Int64:
                  case UInt32:
                  case UInt64:
                     // if we're comparing using 64 bit integers, ignore
                     // differences between 32 bit and 64 bit integers
                     if(flags & DiffIntegersAsInt64s)
                     {
                        // do signed comparison
                        if(source->getType() == Int32 ||
                           source->getType() == Int64)
                        {
                           if(source->getInt64() != target->getInt64())
                           {
                              rval = true;
                              result = target.clone();
                           }
                        }
                        // do unsigned comparison
                        else if(source->getUInt64() != target->getUInt64())
                        {
                           rval = true;
                           result = target.clone();
                        }

                        // only break out of case if we're comparing
                        // using 64 bit integers, otherwise drop to the
                        // default case of a type mismatch
                        break;
                     }
                  default:
                     result = "[DiffError: type mismatch]";
                     rval = true;
               }
            }
            else if(source != target)
            {
               rval = true;
               result = target.clone();
            }
            break;
         case Double:
            // compare doubles as strings if requested
            if((flags & DiffDoublesAsStrings) &&
               source->getType() == target->getType())
            {
               if(strcmp(source->getString(), target->getString()) != 0)
               {
                  rval = true;
                  result = target.clone();
               }
               // only break out of case if comparing as strings
               break;
            }
         case String:
         case Boolean:
            if(source->getType() != target->getType())
            {
               result = "[DiffError: type mismatch]";
               rval = true;
            }
            else if(source != target)
            {
               rval = true;
               result = target.clone();
            }
            break;
         case Map:
            if(source->getType() != target->getType())
            {
               result = "[DiffError: type mismatch, expected Map]";
               rval = true;
            }
            else
            {
               // FIXME: since this code was copied from the config manager
               // this only checks additions and updates not removals which
               // is totally wrong... we need to fix this
               DynamicObjectIterator i = target.getIterator();
               while(i->hasNext())
               {
                  DynamicObject next = i->next();
                  const char* name = i->getName();
                  if(!source->hasMember(name))
                  {
                     // source does not have property that is in target,
                     // so add to diff
                     rval = true;
                     result[name] = next.clone();
                  }
                  else
                  {
                     // recusively get sub-diff
                     DynamicObject d;
                     if(source[name].diff(next, d, flags))
                     {
                        // diff found, add it
                        rval = true;
                        result[name] = d;
                     }
                  }
               }
            }
            // FIXME: search source for items that are not in target

            break;
         case Array:
            if(source->getType() != target->getType())
            {
               result = "[DiffError: type mismatch, expected Array]";
               rval = true;
            }
            else
            {
               // FIXME: since this code was copied from the config manager
               // this only checks additions and updates not removals which
               // is totally wrong... we need to fix this
               DynamicObject temp;
               temp->setType(Array);
               DynamicObjectIterator i = target.getIterator();
               for(int ii = 0; i->hasNext(); ii++)
               {
                  DynamicObject next = i->next();
                  DynamicObject d;
                  if(source->length() < (ii + 1) ||
                     source[ii].diff(next, d, flags))
                  {
                     // diff found
                     rval = true;
                     temp[ii] = d;
                  }
                  else
                  {
                     // set the array value in temp to the value in source
                     // FIXME: should this be set to null or something else
                     // instead since there is no difference?
                     temp[ii] = source[ii];
                  }
               }

               // FIXME: check target for array indexes that are in source

               // only set array to target if a diff was found
               if(rval)
               {
                  result = temp;
               }
            }
            break;
      }
   }

   return rval;
}

void DynamicObject::merge(DynamicObject& rhs, bool append)
{
   switch(rhs->getType())
   {
      case String:
      case Boolean:
      case Int32:
      case UInt32:
      case Int64:
      case UInt64:
      case Double:
         *this = rhs.clone();
         break;
      case Map:
      {
         (*this)->setType(Map);
         DynamicObjectIterator i = rhs.getIterator();
         while(i->hasNext())
         {
            DynamicObject& next = i->next();
            (*this)[i->getName()].merge(next, append);
         }
         break;
      }
      case Array:
         (*this)->setType(Array);
         DynamicObjectIterator i = rhs.getIterator();
         int offset = (append ? (*this)->length() : 0);
         for(int ii = 0; i->hasNext(); ii++)
         {
            (*this)[offset + ii].merge(i->next(), append);
         }
         break;
   }
}

bool DynamicObject::isSubset(const DynamicObject& rhs) const
{
   bool rval;

   rval = Collectable<DynamicObjectImpl>::operator==(rhs);
   if(!rval && (*this)->getType() == Map && rhs->getType() == Map)
   {
      // ensure right map has same or greater length
      if((*this)->length() <= rhs->length())
      {
         rval = true;
         DynamicObjectIterator i = this->getIterator();
         while(rval && i->hasNext())
         {
            DynamicObject& leftDyno = i->next();
            if(rhs->hasMember(i->getName()))
            {
               DynamicObject& rightDyno = (*rhs)[i->getName()];
               if(leftDyno->getType() == Map && rightDyno->getType() == Map)
               {
                  rval = leftDyno.isSubset(rightDyno);
               }
               else
               {
                  rval = (leftDyno == rightDyno);
               }
            }
            else
            {
               rval = false;
            }
         }
      }
   }

   return rval;
}

const char* DynamicObject::descriptionForType(DynamicObjectType type)
{
   const char* rval = NULL;

   switch(type)
   {
      case String:
         rval = "string";
         break;
      case Boolean:
         rval = "boolean";
         break;
      case Int32:
         rval = "32 bit integer";
         break;
      case UInt32:
         rval = "32 bit unsigned integer";
         break;
      case Int64:
         rval = "64 bit integer";
         break;
      case UInt64:
         rval = "64 bit unsigned integer";
         break;
      case Double:
         rval = "floating point";
         break;
      case Map:
         rval = "map";
         break;
      case Array:
         rval = "array";
         break;
   }

   return rval;
}

DynamicObjectType DynamicObject::determineType(const char* str)
{
   DynamicObjectType rval = String;

   // FIXME: this code might interpret hex/octal strings as integers
   // (and other code for that matter!) and we might not want to do that

   // if string starts with whitespace, forget about it
   if(!isspace(str[0]))
   {
      // see if the number is an unsigned int
      // then check signed int
      // then check doubles
      char* end;
      strtoull(str, &end, 10);
      if(end[0] == 0 && str[0] != '-')
      {
         // if end is NULL (and not negative) then the whole string was an int
         rval = UInt64;
      }
      else
      {
         // the number may be a signed int
         strtoll(str, &end, 10);
         if(end[0] == 0)
         {
            // if end is NULL then the whole string was an int
            rval = Int64;
         }
         else
         {
            // the number may be a double
            strtod(str, &end);
            if(end[0] == 0)
            {
               // end is NULL, so we've got a double,
               // else we've assume a String
               rval = Double;
            }
         }
      }
   }

   return rval;
}
<commit_msg>Fixed diffing algorithm for DynamicObject.<commit_after>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/rt/DynamicObject.h"

#include "db/rt/DynamicObjectIterator.h"
#include "db/rt/DynamicObjectIterators.h"

#include <cstdlib>
#include <cctype>

using namespace db::rt;

DynamicObject::DynamicObject() :
   Collectable<DynamicObjectImpl>(new DynamicObjectImpl())
{
}

DynamicObject::DynamicObject(DynamicObjectImpl* impl) :
   Collectable<DynamicObjectImpl>(impl)
{
}

DynamicObject::DynamicObject(const DynamicObject& rhs) :
   Collectable<DynamicObjectImpl>(rhs)
{
}

DynamicObject::~DynamicObject()
{
}

bool DynamicObject::operator==(const DynamicObject& rhs) const
{
   bool rval;

   const DynamicObject& lhs = *this;
   rval = Collectable<DynamicObjectImpl>::operator==(rhs);
   if(!rval && !lhs.isNull() && !rhs.isNull())
   {
      // compare heap objects
      rval = (*lhs == *rhs);
   }

   return rval;
}

bool DynamicObject::operator!=(const DynamicObject& rhs) const
{
   return !(*this == rhs);
}

bool DynamicObject::operator<(const DynamicObject& rhs) const
{
   bool rval;

   const DynamicObject& lhs = *this;

   // NULL is always less than anything other than NULL
   if(lhs.isNull())
   {
      rval = !rhs.isNull();
   }
   // lhs is not NULL, but rhs is, so rhs is not less
   else if(rhs.isNull())
   {
      rval = false;
   }
   // neither lhs or rhs is NULL, compare heap objects
   else
   {
      rval = (*lhs < *rhs);
   }

   return rval;
}

void DynamicObject::operator=(const char* value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(const unsigned char* value)
{
   operator=((const char*)value);
}

void DynamicObject::operator=(bool value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(int32_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(uint32_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(int64_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(uint64_t value)
{
   *mReference->ptr = value;
}

void DynamicObject::operator=(double value)
{
   *mReference->ptr = value;
}

DynamicObject& DynamicObject::operator[](const char* name)
{
   return (*mReference->ptr)[name];
}

DynamicObject& DynamicObject::operator[](const unsigned char* name)
{
   return operator[]((const char*)name);
}

DynamicObject& DynamicObject::operator[](int index)
{
   return (*mReference->ptr)[index];
}

DynamicObjectIterator DynamicObject::getIterator() const
{
   DynamicObjectIteratorImpl* i;

   switch((*this)->getType())
   {
      case Map:
         i = new DynamicObjectIteratorMap((DynamicObject&)*this);
         break;
      case Array:
         i = new DynamicObjectIteratorArray((DynamicObject&)*this);
         break;
      default:
         i = new DynamicObjectIteratorSingle((DynamicObject&)*this);
         break;
   }

   return DynamicObjectIterator(i);
}

DynamicObject DynamicObject::first() const
{
   DynamicObject rval(NULL);

   // return first result of iterator
   DynamicObjectIterator i = getIterator();
   if(i->hasNext())
   {
      rval = i->next();
   }

   return rval;
}

DynamicObject DynamicObject::clone()
{
   DynamicObject rval;

   if(isNull())
   {
      rval.setNull();
   }
   else
   {
      int index = 0;
      rval->setType((*this)->getType());
      DynamicObjectIterator i = getIterator();
      while(i->hasNext())
      {
         DynamicObject dyno = i->next();
         switch((*this)->getType())
         {
            case String:
               rval = dyno->getString();
               break;
            case Boolean:
               rval = dyno->getBoolean();
               break;
            case Int32:
               rval = dyno->getInt32();
               break;
            case UInt32:
               rval = dyno->getUInt32();
               break;
            case Int64:
               rval = dyno->getInt64();
               break;
            case UInt64:
               rval = dyno->getUInt64();
               break;
            case Double:
               rval = dyno->getDouble();
               break;
            case Map:
               rval[i->getName()] = dyno.clone();
               break;
            case Array:
               rval[index++] = dyno.clone();
               break;
         }
      }
   }

   return rval;
}

/**
 * The _getMapDiff helper function gets the differences between the source
 * object and the target object and places the result in the result object.
 * The comparison flags are passed to the diffing algorithm.
 *
 * @param source the source object to compare against the target object.
 * @param target the target object that will be compared against the source
 *               object.
 * @param result the result of the diffing operation.
 * @param flags the flags that will be passed to the recursive diffing
 *              operation.
 *
 * @return true if there are differences, false otherwise.
 */
static bool _getMapDiff(
   DynamicObject& source, DynamicObject& target, DynamicObject& result,
   uint32_t flags)
{
   bool rval = false;

   // Find everything that is in target and not in source
   DynamicObjectIterator i = target.getIterator();
   while(i->hasNext())
   {
      DynamicObject& next = i->next();
      const char* name = i->getName();
      if(!source->hasMember(name))
      {
         // source does not have property that is in target,
         // so add to diff
         rval = true;
         result[name] = next.clone();
      }
      else
      {
         // recusively get sub-diff
         DynamicObject d;
         if(source[name].diff(next, d, flags))
         {
            // diff found, add it
            rval = true;
            result[name] = d;
         }
      }
   }

   return rval;
}

bool DynamicObject::diff(
   DynamicObject& target, DynamicObject& result, uint32_t flags)
{
   bool rval = false;
   DynamicObject& source = (DynamicObject&)*this;
   // clear any old values
   result->clear();

   if(source.isNull() && target.isNull())
   {
      // same: no diff
   }
   else if(!source.isNull() && target.isNull())
   {
      // <stuff> -> NULL: diff=NULL
      rval = true;
      result = "[DiffError: target object is NULL]";
   }
   else if(source.isNull() && !target.isNull())
   {
      // NULL -> <stuff> -or- types differ: diff=target
      rval = true;
      result = "[DiffError: source object is NULL]";
   }
   else
   {
      // not null && same type: diff=deep compare
      switch(source->getType())
      {
         case Int32:
         case Int64:
         case UInt32:
         case UInt64:
            if(source->getType() != target->getType())
            {
               switch(target->getType())
               {
                  case Int32:
                  case Int64:
                  case UInt32:
                  case UInt64:
                     // if we're comparing using 64 bit integers, ignore
                     // differences between 32 bit and 64 bit integers
                     if(flags & DiffIntegersAsInt64s)
                     {
                        // do signed comparison
                        if(source->getType() == Int32 ||
                           source->getType() == Int64)
                        {
                           if(source->getInt64() != target->getInt64())
                           {
                              rval = true;
                              result = target.clone();
                           }
                        }
                        // do unsigned comparison
                        else if(source->getUInt64() != target->getUInt64())
                        {
                           rval = true;
                           result = target.clone();
                        }

                        // only break out of case if we're comparing
                        // using 64 bit integers, otherwise drop to the
                        // default case of a type mismatch
                        break;
                     }
                  default:
                     result = "[DiffError: type mismatch]";
                     rval = true;
               }
            }
            else if(source != target)
            {
               rval = true;
               result = target.clone();
            }
            break;
         case Double:
            // compare doubles as strings if requested
            if((flags & DiffDoublesAsStrings) &&
               source->getType() == target->getType())
            {
               if(strcmp(source->getString(), target->getString()) != 0)
               {
                  rval = true;
                  result = target.clone();
               }
               // only break out of case if comparing as strings
               break;
            }
         case String:
         case Boolean:
            if(source->getType() != target->getType())
            {
               result = "[DiffError: type mismatch]";
               rval = true;
            }
            else if(source != target)
            {
               rval = true;
               result = target.clone();
            }
            break;
         case Map:
            if(source->getType() != target->getType())
            {
               result = "[DiffError: type mismatch, expected Map]";
               rval = true;
            }
            else
            {
               // get the Map differences between source and target
               rval = _getMapDiff(source, target, result, flags) || rval;
               // get the Map differences between target and source
               rval = _getMapDiff(target, source, result, flags) || rval;
            }
            break;
         case Array:
            if(source->getType() != target->getType())
            {
               result = "[DiffError: type mismatch, expected Array]";
               rval = true;
            }
            else
            {
               // FIXME: since this code was copied from the config manager
               // this only checks additions and updates not removals which
               // is totally wrong... we need to fix this
               DynamicObject temp;
               temp->setType(Array);
               DynamicObjectIterator i = target.getIterator();
               for(int ii = 0; i->hasNext(); ii++)
               {
                  DynamicObject next = i->next();
                  DynamicObject d;
                  if(source->length() < (ii + 1) ||
                     source[ii].diff(next, d, flags))
                  {
                     // diff found
                     rval = true;
                     temp[ii] = d;
                  }
                  else
                  {
                     // set the array value in temp to the value in source
                     // FIXME: should this be set to null or something else
                     // instead since there is no difference?
                     temp[ii] = source[ii];
                  }
               }

               // FIXME: check target for array indexes that are in source

               // only set array to target if a diff was found
               if(rval)
               {
                  result = temp;
               }
            }
            break;
      }
   }

   return rval;
}

void DynamicObject::merge(DynamicObject& rhs, bool append)
{
   switch(rhs->getType())
   {
      case String:
      case Boolean:
      case Int32:
      case UInt32:
      case Int64:
      case UInt64:
      case Double:
         *this = rhs.clone();
         break;
      case Map:
      {
         (*this)->setType(Map);
         DynamicObjectIterator i = rhs.getIterator();
         while(i->hasNext())
         {
            DynamicObject& next = i->next();
            (*this)[i->getName()].merge(next, append);
         }
         break;
      }
      case Array:
         (*this)->setType(Array);
         DynamicObjectIterator i = rhs.getIterator();
         int offset = (append ? (*this)->length() : 0);
         for(int ii = 0; i->hasNext(); ii++)
         {
            (*this)[offset + ii].merge(i->next(), append);
         }
         break;
   }
}

bool DynamicObject::isSubset(const DynamicObject& rhs) const
{
   bool rval;

   rval = Collectable<DynamicObjectImpl>::operator==(rhs);
   if(!rval && (*this)->getType() == Map && rhs->getType() == Map)
   {
      // ensure right map has same or greater length
      if((*this)->length() <= rhs->length())
      {
         rval = true;
         DynamicObjectIterator i = this->getIterator();
         while(rval && i->hasNext())
         {
            DynamicObject& leftDyno = i->next();
            if(rhs->hasMember(i->getName()))
            {
               DynamicObject& rightDyno = (*rhs)[i->getName()];
               if(leftDyno->getType() == Map && rightDyno->getType() == Map)
               {
                  rval = leftDyno.isSubset(rightDyno);
               }
               else
               {
                  rval = (leftDyno == rightDyno);
               }
            }
            else
            {
               rval = false;
            }
         }
      }
   }

   return rval;
}

const char* DynamicObject::descriptionForType(DynamicObjectType type)
{
   const char* rval = NULL;

   switch(type)
   {
      case String:
         rval = "string";
         break;
      case Boolean:
         rval = "boolean";
         break;
      case Int32:
         rval = "32 bit integer";
         break;
      case UInt32:
         rval = "32 bit unsigned integer";
         break;
      case Int64:
         rval = "64 bit integer";
         break;
      case UInt64:
         rval = "64 bit unsigned integer";
         break;
      case Double:
         rval = "floating point";
         break;
      case Map:
         rval = "map";
         break;
      case Array:
         rval = "array";
         break;
   }

   return rval;
}

DynamicObjectType DynamicObject::determineType(const char* str)
{
   DynamicObjectType rval = String;

   // FIXME: this code might interpret hex/octal strings as integers
   // (and other code for that matter!) and we might not want to do that

   // if string starts with whitespace, forget about it
   if(!isspace(str[0]))
   {
      // see if the number is an unsigned int
      // then check signed int
      // then check doubles
      char* end;
      strtoull(str, &end, 10);
      if(end[0] == 0 && str[0] != '-')
      {
         // if end is NULL (and not negative) then the whole string was an int
         rval = UInt64;
      }
      else
      {
         // the number may be a signed int
         strtoll(str, &end, 10);
         if(end[0] == 0)
         {
            // if end is NULL then the whole string was an int
            rval = Int64;
         }
         else
         {
            // the number may be a double
            strtod(str, &end);
            if(end[0] == 0)
            {
               // end is NULL, so we've got a double,
               // else we've assume a String
               rval = Double;
            }
         }
      }
   }

   return rval;
}
<|endoftext|>


<commit_before><commit_msg>fixed addevent<commit_after><|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. 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 PX4 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 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.
 *
 ****************************************************************************/

#include "ISM330DLC.hpp"

#include <px4_platform_common/getopt.h>

namespace ism330dlc
{

ISM330DLC *g_dev{nullptr};

int	start(enum Rotation rotation);
int	stop();
int	status();
void	usage();

int start(enum Rotation rotation)
{
	if (g_dev != nullptr) {
		PX4_WARN("already started");
		return 0;
	}

	// create the driver
	g_dev = new ISM330DLC(PX4_SPI_BUS_SENSORS2, PX4_SPIDEV_ISM330, rotation);	// v5x TODO: board manifest

	if (g_dev == nullptr) {
		PX4_ERR("driver start failed");
		return -1;
	}

	if (!g_dev->Init()) {
		PX4_ERR("driver init failed");
		delete g_dev;
		g_dev = nullptr;
		return -1;
	}

	return 0;
}

int stop()
{
	if (g_dev == nullptr) {
		PX4_WARN("driver not running");
	}

	g_dev->Stop();
	delete g_dev;

	return 0;
}

int reset()
{
	if (g_dev == nullptr) {
		PX4_WARN("driver not running");
	}

	return g_dev->Reset();
}

int status()
{
	if (g_dev == nullptr) {
		PX4_WARN("driver not running");
		return -1;
	}

	g_dev->PrintInfo();

	return 0;
}

void usage()
{
	PX4_INFO("missing command: try 'start', 'stop', 'reset', 'status'");
	PX4_INFO("options:");
	PX4_INFO("    -R rotation");
}

} // namespace ism330dlc

extern "C" __EXPORT int ism330dlc_main(int argc, char *argv[])
{
	enum Rotation rotation = ROTATION_NONE;
	int myoptind = 1;
	int ch = 0;
	const char *myoptarg = nullptr;

	/* start options */
	while ((ch = px4_getopt(argc, argv, "R:", &myoptind, &myoptarg)) != EOF) {
		switch (ch) {
		case 'R':
			rotation = (enum Rotation)atoi(myoptarg);
			break;

		default:
			ism330dlc::usage();
			return 0;
		}
	}

	const char *verb = argv[myoptind];

	if (!strcmp(verb, "start")) {
		return ism330dlc::start(rotation);

	} else if (!strcmp(verb, "stop")) {
		return ism330dlc::stop();

	} else if (!strcmp(verb, "status")) {
		return ism330dlc::status();

	} else if (!strcmp(verb, "reset")) {
		return ism330dlc::reset();
	}

	ism330dlc::usage();

	return 0;
}
<commit_msg>Ddded cli check for ism330dlc startup to prevent hardfault if no options are given.<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. 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 PX4 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 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.
 *
 ****************************************************************************/

#include "ISM330DLC.hpp"

#include <px4_platform_common/getopt.h>

namespace ism330dlc
{

ISM330DLC *g_dev{nullptr};

int	start(enum Rotation rotation);
int	stop();
int	status();
void	usage();

int start(enum Rotation rotation)
{
	if (g_dev != nullptr) {
		PX4_WARN("already started");
		return 0;
	}

	// create the driver
	g_dev = new ISM330DLC(PX4_SPI_BUS_SENSORS2, PX4_SPIDEV_ISM330, rotation);	// v5x TODO: board manifest

	if (g_dev == nullptr) {
		PX4_ERR("driver start failed");
		return -1;
	}

	if (!g_dev->Init()) {
		PX4_ERR("driver init failed");
		delete g_dev;
		g_dev = nullptr;
		return -1;
	}

	return 0;
}

int stop()
{
	if (g_dev == nullptr) {
		PX4_WARN("driver not running");
	}

	g_dev->Stop();
	delete g_dev;

	return 0;
}

int reset()
{
	if (g_dev == nullptr) {
		PX4_WARN("driver not running");
	}

	return g_dev->Reset();
}

int status()
{
	if (g_dev == nullptr) {
		PX4_WARN("driver not running");
		return -1;
	}

	g_dev->PrintInfo();

	return 0;
}

void usage()
{
	PX4_INFO("missing command: try 'start', 'stop', 'reset', 'status'");
	PX4_INFO("options:");
	PX4_INFO("    -R rotation");
}

} // namespace ism330dlc

extern "C" __EXPORT int ism330dlc_main(int argc, char *argv[])
{
	enum Rotation rotation = ROTATION_NONE;
	int myoptind = 1;
	int ch = 0;
	const char *myoptarg = nullptr;

	/* start options */
	while ((ch = px4_getopt(argc, argv, "R:", &myoptind, &myoptarg)) != EOF) {
		switch (ch) {
		case 'R':
			rotation = (enum Rotation)atoi(myoptarg);
			break;

		default:
			ism330dlc::usage();
			return 0;
		}
	}

	if (myoptind >= argc) {
		ism330dlc::usage();
		return -1;
	}

	const char *verb = argv[myoptind];

	if (!strcmp(verb, "start")) {
		return ism330dlc::start(rotation);

	} else if (!strcmp(verb, "stop")) {
		return ism330dlc::stop();

	} else if (!strcmp(verb, "status")) {
		return ism330dlc::status();

	} else if (!strcmp(verb, "reset")) {
		return ism330dlc::reset();
	}

	ism330dlc::usage();

	return 0;
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/tensor/sparse/sparse_tensor.h>
#include <vespa/eval/tensor/sparse/sparse_tensor_builder.h>
#include <vespa/eval/tensor/types.h>
#include <vespa/eval/tensor/default_tensor.h>
#include <vespa/eval/tensor/tensor_factory.h>
#include <vespa/eval/tensor/serialization/typed_binary_format.h>
#include <vespa/eval/tensor/serialization/slime_binary_format.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <iostream>

using namespace vespalib::tensor;

template <typename BuilderType>
struct Fixture
{
    BuilderType _builder;
    Fixture() : _builder() {}

    Tensor::UP createTensor(const TensorCells &cells) {
        return vespalib::tensor::TensorFactory::create(cells, _builder);
    }
    Tensor::UP createTensor(const TensorCells &cells, const TensorDimensions &dimensions) {
        return TensorFactory::create(cells, dimensions, _builder);
    }

    static inline uint32_t getTensorTypeId();

    void assertSerialized(const vespalib::string &exp, const TensorCells &rhs,
                          const TensorDimensions &rhsDimensions) {
        Tensor::UP rhsTensor(createTensor(rhs, rhsDimensions));
        auto slime = SlimeBinaryFormat::serialize(*rhsTensor);
        vespalib::Memory memory_exp(exp);
        vespalib::Slime expSlime;
        size_t used = vespalib::slime::JsonFormat::decode(memory_exp, expSlime);
        EXPECT_TRUE(used > 0);
        EXPECT_EQUAL(expSlime, *slime);
    }
};

template <>
uint32_t
Fixture<SparseTensorBuilder>::getTensorTypeId() { return 2u; }

using SparseFixture = Fixture<SparseTensorBuilder>;

namespace {
vespalib::string twoCellsJson[3] =
{
    "{ dimensions: [ 'x', 'y' ],"
    " cells: ["
    "{ address: { y:'3'}, value: 4.0 },"
    "{ address: { x:'1'}, value: 3.0 }"
    "] }",
    "{ dimensions: [ 'x', 'y' ],"
    " cells: ["
    "{ address: { x:'1'}, value: 3.0 },"
    "{ address: { y:'3'}, value: 4.0 }"
    "] }",
    "{ dimensions: [ 'x', 'y' ],"
    " cells: ["
    "{ address: { y:'3'}, value: 4.0 },"
    "{ address: { x:'1'}, value: 3.0 }"
    "] }",
};
}

template <typename FixtureType>
void
testTensorSlimeSerialization(FixtureType &f)
{
    TEST_DO(f.assertSerialized("{ dimensions: [], cells: [] }", {}, {}));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ], cells: [] }",
                               {}, { "x" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ], cells: [] }",
                               {}, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ],"
                               "cells: ["
                               "{ address: { x: '1' }, value: 3.0 }"
                               "] }",
                               { {{{"x","1"}}, 3} }, { "x" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { }, value: 3.0 }"
                               "] }",
                               { {{}, 3} }, { "x", "y"}));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '1' }, value: 3.0 }"
                               "] }",
                               { {{{"x","1"}}, 3} }, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { y: '3' }, value: 3.0 }"
                               "] }",
                               { {{{"y","3"}}, 3} }, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x:'2', y:'4'}, value: 3.0 }"
                               "] }",
                               { {{{"x","2"}, {"y", "4"}}, 3} }, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x:'1'}, value: 3.0 }"
                               "] }",
                               { {{{"x","1"}}, 3} }, {"x", "y"}));
    TEST_DO(f.assertSerialized(twoCellsJson[FixtureType::getTensorTypeId()],
                               { {{{"x","1"}}, 3}, {{{"y","3"}}, 4} },
                               {"x", "y"}));
}

TEST_F("test tensor slime serialization for SparseTensor", SparseFixture)
{
    testTensorSlimeSerialization(f);
}

struct DenseFixture
{
    DenseFixture() {}

    Tensor::UP createTensor(const DenseTensorCells &cells) {
        return vespalib::tensor::TensorFactory::createDense(cells);
    }

    void assertSerialized(const vespalib::string &exp,
                          const DenseTensorCells &rhs) {
        Tensor::UP rhsTensor(createTensor(rhs));
        auto slime = SlimeBinaryFormat::serialize(*rhsTensor);
        vespalib::Memory memory_exp(exp);
        vespalib::Slime expSlime;
        size_t used = vespalib::slime::JsonFormat::decode(memory_exp, expSlime);
        EXPECT_TRUE(used > 0);
        EXPECT_EQUAL(expSlime, *slime);
    }
};

TEST_F("test tensor slime serialization for DenseTensor", DenseFixture)
{
    TEST_DO(f.assertSerialized("{ dimensions: [], cells: ["
                               "{ address: { }, value: 0.0 }"
                               "] }", {}));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ], cells: ["
                               "{ address: { x: '0' }, value: 0.0 }"
                               "] }",
                               { {{{"x",0}}, 0} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ], cells: ["
                               "{ address: { x: '0', y: '0' }, value: 0.0 }"
                               "] }",
                               { {{{"x",0},{"y",0}}, 0} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ],"
                               "cells: ["
                               "{ address: { x: '0' }, value: 0.0 },"
                               "{ address: { x: '1' }, value: 3.0 }"
                               "] }",
                               { {{{"x",1}}, 3} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '0', y: '0' }, value: 3.0 }"
                               "] }",
                               { {{{"x",0},{"y",0}}, 3} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '0', y: '0' }, value: 0.0 },"
                               "{ address: { x: '1', y: '0' }, value: 3.0 }"
                               "] }",
                               { {{{"x",1},{"y", 0}}, 3} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '0', y: '0' }, value: 0.0 },"
                               "{ address: { x: '0', y: '1' }, value: 0.0 },"
                               "{ address: { x: '0', y: '2' }, value: 0.0 },"
                               "{ address: { x: '0', y: '3' }, value: 3.0 }"
                               "] }",
                               { {{{"x",0},{"y",3}}, 3} }));
}

TEST_MAIN() { TEST_RUN_ALL(); }
<commit_msg>Revert earlier reorder.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/tensor/sparse/sparse_tensor.h>
#include <vespa/eval/tensor/sparse/sparse_tensor_builder.h>
#include <vespa/eval/tensor/types.h>
#include <vespa/eval/tensor/default_tensor.h>
#include <vespa/eval/tensor/tensor_factory.h>
#include <vespa/eval/tensor/serialization/typed_binary_format.h>
#include <vespa/eval/tensor/serialization/slime_binary_format.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <iostream>

using namespace vespalib::tensor;

template <typename BuilderType>
struct Fixture
{
    BuilderType _builder;
    Fixture() : _builder() {}

    Tensor::UP createTensor(const TensorCells &cells) {
        return vespalib::tensor::TensorFactory::create(cells, _builder);
    }
    Tensor::UP createTensor(const TensorCells &cells, const TensorDimensions &dimensions) {
        return TensorFactory::create(cells, dimensions, _builder);
    }

    static inline uint32_t getTensorTypeId();

    void assertSerialized(const vespalib::string &exp, const TensorCells &rhs,
                          const TensorDimensions &rhsDimensions) {
        Tensor::UP rhsTensor(createTensor(rhs, rhsDimensions));
        auto slime = SlimeBinaryFormat::serialize(*rhsTensor);
        vespalib::Memory memory_exp(exp);
        vespalib::Slime expSlime;
        size_t used = vespalib::slime::JsonFormat::decode(memory_exp, expSlime);
        EXPECT_TRUE(used > 0);
        EXPECT_EQUAL(expSlime, *slime);
    }
};

template <>
uint32_t
Fixture<SparseTensorBuilder>::getTensorTypeId() { return 2u; }

using SparseFixture = Fixture<SparseTensorBuilder>;

namespace {
vespalib::string twoCellsJson[3] =
{
    "{ dimensions: [ 'x', 'y' ],"
    " cells: ["
    "{ address: { y:'3'}, value: 4.0 },"
    "{ address: { x:'1'}, value: 3.0 }"
    "] }",
    "{ dimensions: [ 'x', 'y' ],"
    " cells: ["
    "{ address: { x:'1'}, value: 3.0 },"
    "{ address: { y:'3'}, value: 4.0 }"
    "] }",
    "{ dimensions: [ 'x', 'y' ],"
    " cells: ["
    "{ address: { x:'1'}, value: 3.0 },"
    "{ address: { y:'3'}, value: 4.0 }"
    "] }",
};
}

template <typename FixtureType>
void
testTensorSlimeSerialization(FixtureType &f)
{
    TEST_DO(f.assertSerialized("{ dimensions: [], cells: [] }", {}, {}));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ], cells: [] }",
                               {}, { "x" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ], cells: [] }",
                               {}, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ],"
                               "cells: ["
                               "{ address: { x: '1' }, value: 3.0 }"
                               "] }",
                               { {{{"x","1"}}, 3} }, { "x" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { }, value: 3.0 }"
                               "] }",
                               { {{}, 3} }, { "x", "y"}));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '1' }, value: 3.0 }"
                               "] }",
                               { {{{"x","1"}}, 3} }, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { y: '3' }, value: 3.0 }"
                               "] }",
                               { {{{"y","3"}}, 3} }, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x:'2', y:'4'}, value: 3.0 }"
                               "] }",
                               { {{{"x","2"}, {"y", "4"}}, 3} }, { "x", "y" }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x:'1'}, value: 3.0 }"
                               "] }",
                               { {{{"x","1"}}, 3} }, {"x", "y"}));
    TEST_DO(f.assertSerialized(twoCellsJson[FixtureType::getTensorTypeId()],
                               { {{{"x","1"}}, 3}, {{{"y","3"}}, 4} },
                               {"x", "y"}));
}

TEST_F("test tensor slime serialization for SparseTensor", SparseFixture)
{
    testTensorSlimeSerialization(f);
}

struct DenseFixture
{
    DenseFixture() {}

    Tensor::UP createTensor(const DenseTensorCells &cells) {
        return vespalib::tensor::TensorFactory::createDense(cells);
    }

    void assertSerialized(const vespalib::string &exp,
                          const DenseTensorCells &rhs) {
        Tensor::UP rhsTensor(createTensor(rhs));
        auto slime = SlimeBinaryFormat::serialize(*rhsTensor);
        vespalib::Memory memory_exp(exp);
        vespalib::Slime expSlime;
        size_t used = vespalib::slime::JsonFormat::decode(memory_exp, expSlime);
        EXPECT_TRUE(used > 0);
        EXPECT_EQUAL(expSlime, *slime);
    }
};

TEST_F("test tensor slime serialization for DenseTensor", DenseFixture)
{
    TEST_DO(f.assertSerialized("{ dimensions: [], cells: ["
                               "{ address: { }, value: 0.0 }"
                               "] }", {}));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ], cells: ["
                               "{ address: { x: '0' }, value: 0.0 }"
                               "] }",
                               { {{{"x",0}}, 0} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ], cells: ["
                               "{ address: { x: '0', y: '0' }, value: 0.0 }"
                               "] }",
                               { {{{"x",0},{"y",0}}, 0} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x' ],"
                               "cells: ["
                               "{ address: { x: '0' }, value: 0.0 },"
                               "{ address: { x: '1' }, value: 3.0 }"
                               "] }",
                               { {{{"x",1}}, 3} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '0', y: '0' }, value: 3.0 }"
                               "] }",
                               { {{{"x",0},{"y",0}}, 3} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '0', y: '0' }, value: 0.0 },"
                               "{ address: { x: '1', y: '0' }, value: 3.0 }"
                               "] }",
                               { {{{"x",1},{"y", 0}}, 3} }));
    TEST_DO(f.assertSerialized("{ dimensions: [ 'x', 'y' ],"
                               " cells: ["
                               "{ address: { x: '0', y: '0' }, value: 0.0 },"
                               "{ address: { x: '0', y: '1' }, value: 0.0 },"
                               "{ address: { x: '0', y: '2' }, value: 0.0 },"
                               "{ address: { x: '0', y: '3' }, value: 3.0 }"
                               "] }",
                               { {{{"x",0},{"y",3}}, 3} }));
}

TEST_MAIN() { TEST_RUN_ALL(); }
<|endoftext|>


<commit_before>#include "reportqueue.h"

#include <chrono>

ReportQueue::ReportQueue(const Config& config_in, std::shared_ptr<HttpInterface> http_client)
    : config(config_in), http(std::move(http_client)) {
  thread_ = std::thread(std::bind(&ReportQueue::run, this));
}

ReportQueue::~ReportQueue() {
  {
    std::lock_guard<std::mutex> lock(m_);
    shutdown_ = true;
  }
  cv_.notify_all();
  thread_.join();

  LOG_DEBUG << "Flushing report queue";
  flushQueue();
}

void ReportQueue::run() {
  // Check if queue is nonempty. If so, move any reports to the Json array and
  // try to send it to the server. Clear the Json array only if the send
  // succeeds.
  std::unique_lock<std::mutex> lock(m_);
  while (!shutdown_) {
    flushQueue();
    cv_.wait_for(lock, std::chrono::seconds(10));
  }
}

void ReportQueue::enqueue(std::unique_ptr<ReportEvent> event) {
  {
    std::lock_guard<std::mutex> lock(m_);
    report_queue_.push(std::move(event));
  }
  cv_.notify_all();
}

void ReportQueue::flushQueue() {
  while (!report_queue_.empty()) {
    report_array.append(report_queue_.front()->toJson());
    report_queue_.pop();
  }

  if (config.tls.server.empty()) {
    // Prevent a lot of unnecessary garbage output in uptane vector tests.
    LOG_TRACE << "No server specified. Clearing report queue.";
    report_array.clear();
  }

  if (!report_array.empty()) {
    HttpResponse response = http->post(config.tls.server + "/events", report_array);

    // 404 implies the server does not support this feature. Nothing we can
    // do, just move along.
    if (response.http_status_code == 404) {
      LOG_TRACE << "Server does not support event reports. Clearing report queue.";
    }

    if (response.isOk() || response.http_status_code == 404) {
      report_array.clear();
    }
  }
}

void ReportEvent::setEcu(const Uptane::EcuSerial& ecu) { custom["ecu"] = ecu.ToString(); }
void ReportEvent::setCorrelationId(const std::string& correlation_id) {
  if (correlation_id != "") {
    custom["correlationId"] = correlation_id;
  }
}

Json::Value ReportEvent::toJson() {
  Json::Value out;

  out["id"] = id;
  out["deviceTime"] = timestamp.ToString();
  out["eventType"]["id"] = type;
  out["eventType"]["version"] = version;
  out["event"] = custom;

  return out;
}

CampaignAcceptedReport::CampaignAcceptedReport(const std::string& campaign_id) : ReportEvent("campaign_accepted", 0) {
  custom["campaignId"] = campaign_id;
}

CampaignDeclinedReport::CampaignDeclinedReport(const std::string& campaign_id) : ReportEvent("campaign_declined", 0) {
  custom["campaignId"] = campaign_id;
}

CampaignPostponedReport::CampaignPostponedReport(const std::string& campaign_id)
    : ReportEvent("campaign_postponed", 0) {
  custom["campaignId"] = campaign_id;
}

DevicePausedReport::DevicePausedReport(const std::string& correlation_id) : ReportEvent("DevicePaused", 0) {
  setCorrelationId(correlation_id);
}

DeviceResumedReport::DeviceResumedReport(const std::string& correlation_id) : ReportEvent("DeviceResumed", 0) {
  setCorrelationId(correlation_id);
}

EcuDownloadStartedReport::EcuDownloadStartedReport(const Uptane::EcuSerial& ecu, const std::string& correlation_id)
    : ReportEvent("EcuDownloadStarted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
}

EcuDownloadCompletedReport::EcuDownloadCompletedReport(const Uptane::EcuSerial& ecu, const std::string& correlation_id,
                                                       bool success)
    : ReportEvent("EcuDownloadCompleted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
  custom["success"] = success;
}

EcuInstallationStartedReport::EcuInstallationStartedReport(const Uptane::EcuSerial& ecu,
                                                           const std::string& correlation_id)
    : ReportEvent("EcuInstallationStarted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
}

EcuInstallationAppliedReport::EcuInstallationAppliedReport(const Uptane::EcuSerial& ecu,
                                                           const std::string& correlation_id)
    : ReportEvent("EcuInstallationApplied", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
}

EcuInstallationCompletedReport::EcuInstallationCompletedReport(const Uptane::EcuSerial& ecu,
                                                               const std::string& correlation_id, bool success)
    : ReportEvent("EcuInstallationCompleted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
  custom["success"] = success;
}
<commit_msg>Less verbose ~ReportQueue()<commit_after>#include "reportqueue.h"

#include <chrono>

ReportQueue::ReportQueue(const Config& config_in, std::shared_ptr<HttpInterface> http_client)
    : config(config_in), http(std::move(http_client)) {
  thread_ = std::thread(std::bind(&ReportQueue::run, this));
}

ReportQueue::~ReportQueue() {
  {
    std::lock_guard<std::mutex> lock(m_);
    shutdown_ = true;
  }
  cv_.notify_all();
  thread_.join();

  LOG_TRACE << "Flushing report queue";
  flushQueue();
}

void ReportQueue::run() {
  // Check if queue is nonempty. If so, move any reports to the Json array and
  // try to send it to the server. Clear the Json array only if the send
  // succeeds.
  std::unique_lock<std::mutex> lock(m_);
  while (!shutdown_) {
    flushQueue();
    cv_.wait_for(lock, std::chrono::seconds(10));
  }
}

void ReportQueue::enqueue(std::unique_ptr<ReportEvent> event) {
  {
    std::lock_guard<std::mutex> lock(m_);
    report_queue_.push(std::move(event));
  }
  cv_.notify_all();
}

void ReportQueue::flushQueue() {
  while (!report_queue_.empty()) {
    report_array.append(report_queue_.front()->toJson());
    report_queue_.pop();
  }

  if (config.tls.server.empty()) {
    // Prevent a lot of unnecessary garbage output in uptane vector tests.
    LOG_TRACE << "No server specified. Clearing report queue.";
    report_array.clear();
  }

  if (!report_array.empty()) {
    HttpResponse response = http->post(config.tls.server + "/events", report_array);

    // 404 implies the server does not support this feature. Nothing we can
    // do, just move along.
    if (response.http_status_code == 404) {
      LOG_TRACE << "Server does not support event reports. Clearing report queue.";
    }

    if (response.isOk() || response.http_status_code == 404) {
      report_array.clear();
    }
  }
}

void ReportEvent::setEcu(const Uptane::EcuSerial& ecu) { custom["ecu"] = ecu.ToString(); }
void ReportEvent::setCorrelationId(const std::string& correlation_id) {
  if (correlation_id != "") {
    custom["correlationId"] = correlation_id;
  }
}

Json::Value ReportEvent::toJson() {
  Json::Value out;

  out["id"] = id;
  out["deviceTime"] = timestamp.ToString();
  out["eventType"]["id"] = type;
  out["eventType"]["version"] = version;
  out["event"] = custom;

  return out;
}

CampaignAcceptedReport::CampaignAcceptedReport(const std::string& campaign_id) : ReportEvent("campaign_accepted", 0) {
  custom["campaignId"] = campaign_id;
}

CampaignDeclinedReport::CampaignDeclinedReport(const std::string& campaign_id) : ReportEvent("campaign_declined", 0) {
  custom["campaignId"] = campaign_id;
}

CampaignPostponedReport::CampaignPostponedReport(const std::string& campaign_id)
    : ReportEvent("campaign_postponed", 0) {
  custom["campaignId"] = campaign_id;
}

DevicePausedReport::DevicePausedReport(const std::string& correlation_id) : ReportEvent("DevicePaused", 0) {
  setCorrelationId(correlation_id);
}

DeviceResumedReport::DeviceResumedReport(const std::string& correlation_id) : ReportEvent("DeviceResumed", 0) {
  setCorrelationId(correlation_id);
}

EcuDownloadStartedReport::EcuDownloadStartedReport(const Uptane::EcuSerial& ecu, const std::string& correlation_id)
    : ReportEvent("EcuDownloadStarted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
}

EcuDownloadCompletedReport::EcuDownloadCompletedReport(const Uptane::EcuSerial& ecu, const std::string& correlation_id,
                                                       bool success)
    : ReportEvent("EcuDownloadCompleted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
  custom["success"] = success;
}

EcuInstallationStartedReport::EcuInstallationStartedReport(const Uptane::EcuSerial& ecu,
                                                           const std::string& correlation_id)
    : ReportEvent("EcuInstallationStarted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
}

EcuInstallationAppliedReport::EcuInstallationAppliedReport(const Uptane::EcuSerial& ecu,
                                                           const std::string& correlation_id)
    : ReportEvent("EcuInstallationApplied", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
}

EcuInstallationCompletedReport::EcuInstallationCompletedReport(const Uptane::EcuSerial& ecu,
                                                               const std::string& correlation_id, bool success)
    : ReportEvent("EcuInstallationCompleted", 0) {
  setEcu(ecu);
  setCorrelationId(correlation_id);
  custom["success"] = success;
}
<|endoftext|>


<commit_before>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  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.                                   */
/*                                                                                */
/*  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 HOLDER 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.                      */
/*                                                                                */
/**************************************************************************************/

#include "BaseDemo.hpp"
#include <vlGraphics/Effect.hpp>
#include <vlGraphics/Geometry.hpp>
#include <vlGraphics/GLSL.hpp>
#include <vlGraphics/GeometryPrimitives.hpp>

#include <vlCore/FileSystem.hpp>

class App_TessellationShader: public BaseDemo
{
public:
  void initEvent()
  {
    vl::Log::info(appletInfo());

    if(!vl::Has_GL_Version_4_0)
    {
      vl::Log::error("This test requires OpenGL 4!\n");
      vl::Time::sleep(2000);
      exit(1);
    }

    const int   patch_count      = 128;
    const float world_size       = 2500.0;
    const float height_scale     = 150.0;
    const float pixel_per_edge   = 16.0f;
    const float max_tessellation = 64.0f;

    vl::ref< vl::Geometry > geom_patch = makeGrid( vl::vec3(), world_size, world_size, patch_count, patch_count, false );

    geom_patch->toGenericVertexAttribs();

    // patch parameter associated to the draw call
    vl::ref<vl::PatchParameter> patch_param = new vl::PatchParameter;
    patch_param->setPatchVertices(4);
    geom_patch->drawCalls()->at(0)->setPatchParameter( patch_param.get() );
    geom_patch->drawCalls()->at(0)->setPrimitiveType(vl::PT_PATCHES);

    vl::ref<vl::Texture> hmap = new vl::Texture("/images/ps_height_4k.jpg", vl::TF_RED, false, false);
    vl::ref<vl::Texture> tmap = new vl::Texture("/images/ps_texture_4k.jpg", vl::TF_RGBA, true, false);

    hmap->getTexParameter()->setMinFilter(vl::TPF_LINEAR);
    hmap->getTexParameter()->setMagFilter(vl::TPF_LINEAR);

    // tessellated patches fx
    vl::ref<vl::Effect> fx = new vl::Effect;
    fx->shader()->enable(vl::EN_DEPTH_TEST);
    fx->shader()->gocTextureUnit(0)->setTexture( hmap.get() );
    fx->shader()->gocTextureUnit(1)->setTexture( tmap.get() );

    // bind all the necessary stages to the GLSLProgram
    mGLSL = fx->shader()->gocGLSLProgram();
    mGLSL->attachShader( new vl::GLSLVertexShader("glsl/tess_grid.vs") );
    mGLSL->attachShader( new vl::GLSLTessControlShader("glsl/tess_grid.tcs") );
    mGLSL->attachShader( new vl::GLSLTessEvaluationShader("glsl/tess_grid.tes") );
    mGLSL->attachShader( new vl::GLSLFragmentShader("glsl/tess_grid.fs") );
    mGLSL->gocUniform("pixel_per_edge")->setUniformF(pixel_per_edge);
    mGLSL->gocUniform("max_tessellation")->setUniformF(max_tessellation);
    mGLSL->gocUniform("screen_size")->setUniform(vl::fvec2(512,512));
    mGLSL->gocUniform("world_size")->setUniformF(world_size);
    mGLSL->gocUniform("height_scale")->setUniformF(height_scale);
    mGLSL->gocUniform("tex_heghtmap")->setUniformI(0);
    mGLSL->gocUniform("tex_diffuse")->setUniformI(1);

    mGLSL->addAutoAttribLocation( "vl_Position", 0 );

    // tessellated patches fx_wire
    vl::ref<vl::Effect> fx_wire = new vl::Effect;
    fx_wire->shader()->enable(vl::EN_DEPTH_TEST);
    fx_wire->shader()->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
    fx_wire->shader()->gocTextureUnit(0)->setTexture( hmap.get() );
    fx_wire->shader()->gocPolygonOffset()->set(-1.0f, -1.0f);
    fx_wire->shader()->enable(vl::EN_POLYGON_OFFSET_LINE);

    // bind all the necessary stages to the GLSLProgram
    mGLSLWire = fx_wire->shader()->gocGLSLProgram();
    mGLSLWire->attachShader( new vl::GLSLVertexShader("glsl/tess_grid.vs") );
    mGLSLWire->attachShader( new vl::GLSLTessControlShader("glsl/tess_grid.tcs") );
    mGLSLWire->attachShader( new vl::GLSLTessEvaluationShader("glsl/tess_grid.tes") );
    mGLSLWire->attachShader( new vl::GLSLFragmentShader("glsl/tess_grid_wire.fs") );
    mGLSLWire->gocUniform("pixel_per_edge")->setUniformF(pixel_per_edge);
    mGLSLWire->gocUniform("max_tessellation")->setUniformF(max_tessellation);
    mGLSLWire->gocUniform("screen_size")->setUniform(vl::fvec2(512,512));
    mGLSLWire->gocUniform("world_size")->setUniformF(world_size);
    mGLSLWire->gocUniform("height_scale")->setUniformF(height_scale);
    mGLSLWire->gocUniform("tex_heghtmap")->setUniformI(0);
    mGLSLWire->gocUniform("wire_color")->setUniform(vl::lightgreen);

    mGLSLWire->addAutoAttribLocation( "vl_Position", 0 );

    sceneManager()->tree()->addActor( geom_patch.get(), fx.get(), NULL )->setRenderRank(0);

    mWireActor = sceneManager()->tree()->addActor( geom_patch.get(), fx_wire.get(), NULL );
    mWireActor->setRenderRank(1);

    // debugging
    #if 0
      // base patch grid
      vl::ref< vl::Geometry > geom_quads = makeGrid(vl::fvec3(), world_size,world_size, patch_count,patch_count, true);
      geom_quads->setColor(vl::red);
      // base patch grid fx
      vl::ref<vl::Effect> fx_grid = new vl::Effect;
      fx_grid->shader()->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
      // add grid
      sceneManager()->tree()->addActor( geom_quads.get(), fx_grid.get(), NULL )->setRenderRank(2);
    #endif
  }

  // interactively change the inner/outer tessellation levels
  void keyPressEvent(unsigned short, vl::EKey key)
  {
    if (key == vl::Key_Space)
      mWireActor->setEnableMask( mWireActor->enableMask() ? 0 : 1 );
  }

  void resizeEvent(int w, int h)
  {
    BaseDemo::resizeEvent(w,h);
    mGLSL->gocUniform("screen_size")->setUniform(vl::fvec2((float)w,(float)h));
    mGLSLWire->gocUniform("screen_size")->setUniform(vl::fvec2((float)w,(float)h));
  }

protected:
  vl::GLSLProgram* mGLSL;
  vl::GLSLProgram* mGLSLWire;
  vl::Actor* mWireActor;
};

// Have fun!

BaseDemo* Create_App_TessellationShader() { return new App_TessellationShader; }

class App_TessellationShaderTri: public BaseDemo
{
public:
  void initEvent()
  {
    vl::Log::info(appletInfo());

    // hemisphere base geometry
    vl::ref< vl::Geometry > geom_patch = new vl::Geometry;

    // hemisphere base geometry vertices
    vl::ref<vl::ArrayFloat3 > verts = new vl::ArrayFloat3;
    verts->resize(12);

    verts->at(0)  = vl::fvec3(1,0,0);
    verts->at(1)  = vl::fvec3(0,1,0);
    verts->at(2)  = vl::fvec3(0,0,1);

    verts->at(3)  = vl::fvec3(1,0,0);
    verts->at(4)  = vl::fvec3(0,0,-1);
    verts->at(5)  = vl::fvec3(0,1,0);

    verts->at(6)  = vl::fvec3(0,0,-1);
    verts->at(7)  = vl::fvec3(-1,0,0);
    verts->at(8)  = vl::fvec3(0,1,0);

    verts->at(9)  = vl::fvec3(-1,0,0);
    verts->at(10) = vl::fvec3(0,0,1);
    verts->at(11) = vl::fvec3(0,1,0);

    // hemisphere base geometry vertex colors
    vl::ref<vl::ArrayFloat3 > cols = new vl::ArrayFloat3;
    cols->resize(12);

    cols->at(0)  = vl::fvec3(1,0,0);
    cols->at(1)  = vl::fvec3(1,0,0);
    cols->at(2)  = vl::fvec3(1,0,0);

    cols->at(3)  = vl::fvec3(0,1,0);
    cols->at(4)  = vl::fvec3(0,1,0);
    cols->at(5)  = vl::fvec3(0,1,0);

    cols->at(6)  = vl::fvec3(1,1,0);
    cols->at(7)  = vl::fvec3(1,1,0);
    cols->at(8)  = vl::fvec3(1,1,0);

    cols->at(9)  = vl::fvec3(0,0,1);
    cols->at(10) = vl::fvec3(0,0,1);
    cols->at(11) = vl::fvec3(0,0,1);

    // vertex array
    geom_patch->setVertexArray( verts.get() );

    // color array
    geom_patch->setColorArray( cols.get() );

    // draw call
    vl::ref< vl::DrawArrays> da = new vl::DrawArrays(vl::PT_PATCHES, 0, verts->size());
    geom_patch->drawCalls()->push_back(da.get());

    // patch parameter associated to the draw call
    vl::ref<vl::PatchParameter> patch_param = new vl::PatchParameter;
    patch_param->setPatchVertices(3);
    da->setPatchParameter( patch_param.get() );

    // effect: light + depth testing
    vl::ref<vl::Effect> fx = new vl::Effect;
    fx->shader()->enable(vl::EN_DEPTH_TEST);

    // bind all the necessary stages to the GLSLProgram
    mGLSL = fx->shader()->gocGLSLProgram();
    mGLSL->attachShader( new vl::GLSLVertexShader("glsl/smooth_triangle.vs") );
    mGLSL->attachShader( new vl::GLSLTessControlShader("glsl/smooth_triangle.tcs") );
    mGLSL->attachShader( new vl::GLSLTessEvaluationShader("glsl/smooth_triangle.tes") );
    mGLSL->attachShader( new vl::GLSLGeometryShader("glsl/smooth_triangle.gs") );
    mGLSL->gocUniform("Outer")->setUniformF(10.0f);
    mGLSL->gocUniform("Inner")->setUniformF(10.0f);
    mGLSL->gocUniform("Radius")->setUniformF(1.0f);

    sceneManager()->tree()->addActor( geom_patch.get(), fx.get(), NULL );
  }

  // interactively change the inner/outer tessellation levels
  void keyPressEvent(unsigned short, vl::EKey key)
  {
    float outer = 0;
    float inner = 0;
    mGLSL->gocUniform("Outer")->getUniform(&outer);
    mGLSL->gocUniform("Inner")->getUniform(&inner);

    if (key == vl::Key_Left)
      outer--;
    else
    if (key == vl::Key_Right)
      outer++;
    else
    if (key == vl::Key_Down)
      inner--;
    else
    if (key == vl::Key_Up)
      inner++;

    inner = inner < 1 ? 1 : inner;
    outer = outer < 1 ? 1 : outer;

    mGLSL->gocUniform("Outer")->setUniformF(outer);
    mGLSL->gocUniform("Inner")->setUniformF(inner);

    vl::Log::print( vl::Say("outer = %n, inner = %n\n") << outer << inner );
  }

protected:
  vl::GLSLProgram* mGLSL;
};

// Have fun!

BaseDemo* Create_App_TessellationShaderTri() { return new App_TessellationShaderTri; }
<commit_msg>use convertToVertexAttribs()<commit_after>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  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.                                   */
/*                                                                                */
/*  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 HOLDER 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.                      */
/*                                                                                */
/**************************************************************************************/

#include "BaseDemo.hpp"
#include <vlGraphics/Effect.hpp>
#include <vlGraphics/Geometry.hpp>
#include <vlGraphics/GLSL.hpp>
#include <vlGraphics/GeometryPrimitives.hpp>

#include <vlCore/FileSystem.hpp>

class App_TessellationShader: public BaseDemo
{
public:
  void initEvent()
  {
    vl::Log::info(appletInfo());

    if(!vl::Has_GL_Version_4_0)
    {
      vl::Log::error("This test requires OpenGL 4!\n");
      vl::Time::sleep(2000);
      exit(1);
    }

    const int   patch_count      = 128;
    const float world_size       = 2500.0;
    const float height_scale     = 150.0;
    const float pixel_per_edge   = 16.0f;
    const float max_tessellation = 64.0f;

    vl::ref< vl::Geometry > geom_patch = makeGrid( vl::vec3(), world_size, world_size, patch_count, patch_count, false );

    geom_patch->convertToVertexAttribs();

    // patch parameter associated to the draw call
    vl::ref<vl::PatchParameter> patch_param = new vl::PatchParameter;
    patch_param->setPatchVertices(4);
    geom_patch->drawCalls()->at(0)->setPatchParameter( patch_param.get() );
    geom_patch->drawCalls()->at(0)->setPrimitiveType(vl::PT_PATCHES);

    vl::ref<vl::Texture> hmap = new vl::Texture("/images/ps_height_4k.jpg", vl::TF_RED, false, false);
    vl::ref<vl::Texture> tmap = new vl::Texture("/images/ps_texture_4k.jpg", vl::TF_RGBA, true, false);

    hmap->getTexParameter()->setMinFilter(vl::TPF_LINEAR);
    hmap->getTexParameter()->setMagFilter(vl::TPF_LINEAR);

    // tessellated patches fx
    vl::ref<vl::Effect> fx = new vl::Effect;
    fx->shader()->enable(vl::EN_DEPTH_TEST);
    fx->shader()->gocTextureUnit(0)->setTexture( hmap.get() );
    fx->shader()->gocTextureUnit(1)->setTexture( tmap.get() );

    // bind all the necessary stages to the GLSLProgram
    mGLSL = fx->shader()->gocGLSLProgram();
    mGLSL->attachShader( new vl::GLSLVertexShader("glsl/tess_grid.vs") );
    mGLSL->attachShader( new vl::GLSLTessControlShader("glsl/tess_grid.tcs") );
    mGLSL->attachShader( new vl::GLSLTessEvaluationShader("glsl/tess_grid.tes") );
    mGLSL->attachShader( new vl::GLSLFragmentShader("glsl/tess_grid.fs") );
    mGLSL->gocUniform("pixel_per_edge")->setUniformF(pixel_per_edge);
    mGLSL->gocUniform("max_tessellation")->setUniformF(max_tessellation);
    mGLSL->gocUniform("screen_size")->setUniform(vl::fvec2(512,512));
    mGLSL->gocUniform("world_size")->setUniformF(world_size);
    mGLSL->gocUniform("height_scale")->setUniformF(height_scale);
    mGLSL->gocUniform("tex_heghtmap")->setUniformI(0);
    mGLSL->gocUniform("tex_diffuse")->setUniformI(1);

    mGLSL->addAutoAttribLocation( "vl_Position", 0 );

    // tessellated patches fx_wire
    vl::ref<vl::Effect> fx_wire = new vl::Effect;
    fx_wire->shader()->enable(vl::EN_DEPTH_TEST);
    fx_wire->shader()->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
    fx_wire->shader()->gocTextureUnit(0)->setTexture( hmap.get() );
    fx_wire->shader()->gocPolygonOffset()->set(-1.0f, -1.0f);
    fx_wire->shader()->enable(vl::EN_POLYGON_OFFSET_LINE);

    // bind all the necessary stages to the GLSLProgram
    mGLSLWire = fx_wire->shader()->gocGLSLProgram();
    mGLSLWire->attachShader( new vl::GLSLVertexShader("glsl/tess_grid.vs") );
    mGLSLWire->attachShader( new vl::GLSLTessControlShader("glsl/tess_grid.tcs") );
    mGLSLWire->attachShader( new vl::GLSLTessEvaluationShader("glsl/tess_grid.tes") );
    mGLSLWire->attachShader( new vl::GLSLFragmentShader("glsl/tess_grid_wire.fs") );
    mGLSLWire->gocUniform("pixel_per_edge")->setUniformF(pixel_per_edge);
    mGLSLWire->gocUniform("max_tessellation")->setUniformF(max_tessellation);
    mGLSLWire->gocUniform("screen_size")->setUniform(vl::fvec2(512,512));
    mGLSLWire->gocUniform("world_size")->setUniformF(world_size);
    mGLSLWire->gocUniform("height_scale")->setUniformF(height_scale);
    mGLSLWire->gocUniform("tex_heghtmap")->setUniformI(0);
    mGLSLWire->gocUniform("wire_color")->setUniform(vl::lightgreen);

    mGLSLWire->addAutoAttribLocation( "vl_Position", 0 );

    sceneManager()->tree()->addActor( geom_patch.get(), fx.get(), NULL )->setRenderRank(0);

    mWireActor = sceneManager()->tree()->addActor( geom_patch.get(), fx_wire.get(), NULL );
    mWireActor->setRenderRank(1);

    // debugging
    #if 0
      // base patch grid
      vl::ref< vl::Geometry > geom_quads = makeGrid(vl::fvec3(), world_size,world_size, patch_count,patch_count, true);
      geom_quads->setColor(vl::red);
      // base patch grid fx
      vl::ref<vl::Effect> fx_grid = new vl::Effect;
      fx_grid->shader()->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
      // add grid
      sceneManager()->tree()->addActor( geom_quads.get(), fx_grid.get(), NULL )->setRenderRank(2);
    #endif
  }

  // interactively change the inner/outer tessellation levels
  void keyPressEvent(unsigned short, vl::EKey key)
  {
    if (key == vl::Key_Space)
      mWireActor->setEnableMask( mWireActor->enableMask() ? 0 : 1 );
  }

  void resizeEvent(int w, int h)
  {
    BaseDemo::resizeEvent(w,h);
    mGLSL->gocUniform("screen_size")->setUniform(vl::fvec2((float)w,(float)h));
    mGLSLWire->gocUniform("screen_size")->setUniform(vl::fvec2((float)w,(float)h));
  }

protected:
  vl::GLSLProgram* mGLSL;
  vl::GLSLProgram* mGLSLWire;
  vl::Actor* mWireActor;
};

// Have fun!

BaseDemo* Create_App_TessellationShader() { return new App_TessellationShader; }

class App_TessellationShaderTri: public BaseDemo
{
public:
  void initEvent()
  {
    vl::Log::info(appletInfo());

    // hemisphere base geometry
    vl::ref< vl::Geometry > geom_patch = new vl::Geometry;

    // hemisphere base geometry vertices
    vl::ref<vl::ArrayFloat3 > verts = new vl::ArrayFloat3;
    verts->resize(12);

    verts->at(0)  = vl::fvec3(1,0,0);
    verts->at(1)  = vl::fvec3(0,1,0);
    verts->at(2)  = vl::fvec3(0,0,1);

    verts->at(3)  = vl::fvec3(1,0,0);
    verts->at(4)  = vl::fvec3(0,0,-1);
    verts->at(5)  = vl::fvec3(0,1,0);

    verts->at(6)  = vl::fvec3(0,0,-1);
    verts->at(7)  = vl::fvec3(-1,0,0);
    verts->at(8)  = vl::fvec3(0,1,0);

    verts->at(9)  = vl::fvec3(-1,0,0);
    verts->at(10) = vl::fvec3(0,0,1);
    verts->at(11) = vl::fvec3(0,1,0);

    // hemisphere base geometry vertex colors
    vl::ref<vl::ArrayFloat3 > cols = new vl::ArrayFloat3;
    cols->resize(12);

    cols->at(0)  = vl::fvec3(1,0,0);
    cols->at(1)  = vl::fvec3(1,0,0);
    cols->at(2)  = vl::fvec3(1,0,0);

    cols->at(3)  = vl::fvec3(0,1,0);
    cols->at(4)  = vl::fvec3(0,1,0);
    cols->at(5)  = vl::fvec3(0,1,0);

    cols->at(6)  = vl::fvec3(1,1,0);
    cols->at(7)  = vl::fvec3(1,1,0);
    cols->at(8)  = vl::fvec3(1,1,0);

    cols->at(9)  = vl::fvec3(0,0,1);
    cols->at(10) = vl::fvec3(0,0,1);
    cols->at(11) = vl::fvec3(0,0,1);

    // vertex array
    geom_patch->setVertexArray( verts.get() );

    // color array
    geom_patch->setColorArray( cols.get() );

    // draw call
    vl::ref< vl::DrawArrays> da = new vl::DrawArrays(vl::PT_PATCHES, 0, verts->size());
    geom_patch->drawCalls()->push_back(da.get());

    // patch parameter associated to the draw call
    vl::ref<vl::PatchParameter> patch_param = new vl::PatchParameter;
    patch_param->setPatchVertices(3);
    da->setPatchParameter( patch_param.get() );

    // effect: light + depth testing
    vl::ref<vl::Effect> fx = new vl::Effect;
    fx->shader()->enable(vl::EN_DEPTH_TEST);

    // bind all the necessary stages to the GLSLProgram
    mGLSL = fx->shader()->gocGLSLProgram();
    mGLSL->attachShader( new vl::GLSLVertexShader("glsl/smooth_triangle.vs") );
    mGLSL->attachShader( new vl::GLSLTessControlShader("glsl/smooth_triangle.tcs") );
    mGLSL->attachShader( new vl::GLSLTessEvaluationShader("glsl/smooth_triangle.tes") );
    mGLSL->attachShader( new vl::GLSLGeometryShader("glsl/smooth_triangle.gs") );
    mGLSL->gocUniform("Outer")->setUniformF(10.0f);
    mGLSL->gocUniform("Inner")->setUniformF(10.0f);
    mGLSL->gocUniform("Radius")->setUniformF(1.0f);

    sceneManager()->tree()->addActor( geom_patch.get(), fx.get(), NULL );
  }

  // interactively change the inner/outer tessellation levels
  void keyPressEvent(unsigned short, vl::EKey key)
  {
    float outer = 0;
    float inner = 0;
    mGLSL->gocUniform("Outer")->getUniform(&outer);
    mGLSL->gocUniform("Inner")->getUniform(&inner);

    if (key == vl::Key_Left)
      outer--;
    else
    if (key == vl::Key_Right)
      outer++;
    else
    if (key == vl::Key_Down)
      inner--;
    else
    if (key == vl::Key_Up)
      inner++;

    inner = inner < 1 ? 1 : inner;
    outer = outer < 1 ? 1 : outer;

    mGLSL->gocUniform("Outer")->setUniformF(outer);
    mGLSL->gocUniform("Inner")->setUniformF(inner);

    vl::Log::print( vl::Say("outer = %n, inner = %n\n") << outer << inner );
  }

protected:
  vl::GLSLProgram* mGLSL;
};

// Have fun!

BaseDemo* Create_App_TessellationShaderTri() { return new App_TessellationShaderTri; }
<|endoftext|>


<commit_before><commit_msg><commit_after><|endoftext|>


<commit_before><commit_msg>we want the b2BodyConfig typedef to be nested from within the physics class since it is physics engine specific<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <unordered_map>
#include <utility>

using namespace std;
struct RandomListNode {
      int label;
      RandomListNode *next, *random;
      RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
};

class Solution {
public:
    RandomListNode *copyRandomList(RandomListNode *head) {
        if (head == NULL) return NULL;
        unordered_map<RandomListNode*, RandomListNode*> p2p;

        RandomListNode* newhead = new RandomListNode(head->label);
        newhead->random = head->random;
        p2p.insert(pair<RandomListNode*, RandomListNode*>(head, newhead));

        RandomListNode* tail = newhead;
        head = head->next;

        while (head != NULL) {
            RandomListNode* item = new RandomListNode(head->label);
            item->random = head->random;
            p2p.insert(pair<RandomListNode*, RandomListNode*>(head, item));

            tail->next = item;
            tail = item;
            head = head->next;
        }

        tail = newhead;
        while (tail != NULL) {
            if (tail->random != NULL) {
                tail->random = p2p.find(tail->random)->second;
            }
            tail = tail->next;
        }
        return newhead;
    }
};

void print_list(RandomListNode* head) {
    while (head != NULL) {
        cout<<head->label;
        if (head->next == NULL) {
            cout<<", next=null";
        } else {
            cout<<", next="<<head->next->label;
        }
        if (head->random == NULL) {
            cout<<", rnd=null";
        } else {
            cout<<", rnd="<<head->random->label;
        }
        cout<<endl;
        head = head->next;
    }
}

int main() {
    RandomListNode* items[10];
    for (int i=0; i<10; i++) {
        items[i] = new RandomListNode(i);
    }

    for (int i=0; i<9; i++) {
        items[i]->next = items[i+1];
    }
    items[0]->next = NULL;
    items[2]->random = items[4];
    items[5]->random = items[1];
    items[8]->random = items[3];

    print_list(items[0]);
    Solution s;
    RandomListNode* ret = s.copyRandomList(items[0]);

    cout<<"==="<<endl;
    print_list(ret);
    return 0;
}
<commit_msg>Add another sulotion for Leetcode Problem: CopyListWithRandomPointer<commit_after>#include <iostream>
#include <unordered_map>
#include <utility>

using namespace std;
struct RandomListNode {
      int label;
      RandomListNode *next, *random;
      RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
};

class Solution {
public:
    // 1. with a map
    RandomListNode *copyRandomList(RandomListNode *head) {
        if (head == NULL) return NULL;
        unordered_map<RandomListNode*, RandomListNode*> p2p;

        RandomListNode* newhead = new RandomListNode(head->label);
        newhead->random = head->random;
        p2p.insert(pair<RandomListNode*, RandomListNode*>(head, newhead));

        RandomListNode* tail = newhead;
        head = head->next;

        while (head != NULL) {
            RandomListNode* item = new RandomListNode(head->label);
            item->random = head->random;
            p2p.insert(pair<RandomListNode*, RandomListNode*>(head, item));

            tail->next = item;
            tail = item;
            head = head->next;
        }

        tail = newhead;
        while (tail != NULL) {
            if (tail->random != NULL) {
                tail->random = p2p.find(tail->random)->second;
            }
            tail = tail->next;
        }
        return newhead;
    }

    // 2. without a map
    RandomListNode *_copyRandomList(RandomListNode *head) {
        if (head == NULL) return NULL;

        RandomListNode* item = new RandomListNode(head->label);
        item->random = head->random;
        item->next = head->next;
        head->next = item;

        RandomListNode* tail = item->next;

        while (tail != NULL) {
            item = new RandomListNode(tail->label);
            item->random = tail->random;
            item->next = tail->next;
            tail->next = item;

            tail = item->next;
        }
        tail = head;
        while (tail != NULL) {
            tail = tail->next;
            if (tail->random != NULL) tail->random = tail->random->next;
            tail = tail->next;
        }

        RandomListNode* newhead = head->next;
        RandomListNode* oldtail = head;
        tail = newhead;
        while (tail->next != NULL) {
            oldtail->next = tail->next;
            oldtail = tail->next;
            tail->next = oldtail->next;
            tail = oldtail->next;
        }
        oldtail->next = NULL;
        return newhead;
    }
};

void print_list(RandomListNode* head) {
    while (head != NULL) {
        cout<<head->label;
        if (head->next == NULL) {
            cout<<", next=null";
        } else {
            cout<<", next="<<head->next->label;
        }
        if (head->random == NULL) {
            cout<<", rnd=null";
        } else {
            cout<<", rnd="<<head->random->label;
        }
        cout<<endl;
        head = head->next;
    }
}

int main() {
    RandomListNode* items[10];
    for (int i=0; i<10; i++) {
        items[i] = new RandomListNode(i);
    }

    for (int i=0; i<9; i++) {
        items[i]->next = items[i+1];
    }
    items[2]->random = items[4];
    items[5]->random = items[1];
    items[8]->random = items[3];

    print_list(items[0]);
    Solution s;
    RandomListNode* ret = s._copyRandomList(items[0]);

    cout<<"==="<<endl;
    print_list(ret);
    return 0;
}
<|endoftext|>