Author Topic: -+{ Challenge }+- Serialize Xdata  (Read 9019 times)

0 Members and 1 Guest are viewing this topic.

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #15 on: January 22, 2010, 08:32:55 AM »
...If I don't misundertand the challenge, here're my C# 2 cents....
The data needs to be in the same format as before it was serialized. I.e.
you would need to read the data back into a Resultbuffer/TypedVale[]

gile

  • Water Moccasin
  • Posts: 2233
  • Marseille, France
Re: -+{ Challenge }+- Serialize Xdata
« Reply #16 on: January 22, 2010, 02:02:03 PM »
I try using an XML file, it's not very fast :|

Code: [Select]
using System;
using System.Text;
using System.Xml;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace SerializeChallenge
{
    public class Class1
    {
        [CommandMethod("Test")]
        public void Test()
        {
            DateTime t0 = DateTime.Now;
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            string filename = "C:\\SerializeChallenge.xml";
            XmlTextWriter writer = new XmlTextWriter(filename, Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument();
            writer.WriteStartElement("SerializeChallenge");
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr =
                    (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                foreach (ObjectId id in btr)
                {
                    Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead, false);
                    ResultBuffer resbuf = ent.XData;
                    if (resbuf == null)
                        continue;
                    writer.WriteStartElement("resbuf");
                    TypedValue[] tvs = resbuf.AsArray();
                    foreach (TypedValue tv in tvs)
                    {
                        writer.WriteStartElement("xdata");
                        writer.WriteAttributeString("code", tv.TypeCode.ToString());
                        writer.WriteAttributeString("value", tv.Value.ToString());
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                }
                tr.Commit();
            }
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            writer.Close();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filename);
            foreach (XmlNode xdatas in xmlDoc.ChildNodes[1].ChildNodes)
            {
                ResultBuffer resbuf = new ResultBuffer();
                foreach (XmlNode data in xdatas.ChildNodes)
                {
                    XmlAttributeCollection atts = data.Attributes;
                    short code = Convert.ToInt16(atts["code"].Value);
                    resbuf.Add(new TypedValue(
                        code,
                        GetValue(code, atts["value"].Value)));
                }
            }
            DateTime t1 = DateTime.Now;
            TimeSpan ts = t1 - t0;
            ed.WriteMessage("\nEllapsed milliseconds: " + ts.TotalMilliseconds.ToString());
        }

        private object GetValue(short code, string p)
        {
            switch (code)
            {
                case 1010:
                    return StringToPoint(p);
                case 1040:
                    return Convert.ToDouble(p);
                case 1070:
                    return Convert.ToInt32(p);
                default:
                    return p;
            }
        }

        private Point3d StringToPoint(string p)
        {
            string[] strs = p.Trim(new char[] { '(', ')' }).Split(new char[] { ',' });
            double[] coords = new double[3];
            for (int i = 0; i < 3; i++)
            {
                coords[i] = Convert.ToDouble(strs[i]);
            }
            return new Point3d(coords);
        }
    }
}
Quote
Commande: test
Ellapsed milliseconds: 7515.625
Commande:
TEST
Ellapsed milliseconds: 6765.625
Commande:
TEST
Ellapsed milliseconds: 7046.875
Commande:
TEST
Ellapsed milliseconds: 7296.875

I try making Serializable classes too but i can't get it work :|
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 2233
  • Marseille, France
Re: -+{ Challenge }+- Serialize Xdata
« Reply #17 on: January 22, 2010, 04:58:28 PM »
I tried to optimize the upper routine but don't win so much.

Code: [Select]
using System;
using System.Text;
using System.Xml;
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace SerializeChallenge
{
    public class Class1
    {
        [CommandMethod("gileCs")]
        public void Test()
        {
            DateTime t0 = DateTime.Now;
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            string filename = "C:\\SerializeChallenge.xml";
            XmlTextWriter writer = new XmlTextWriter(filename, Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument();
            writer.WriteStartElement("SerializeChallenge");
            int cnt = 0;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr =
                    (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                foreach (ObjectId id in btr)
                {
                    Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead, false);
                    ResultBuffer resbuf = ent.XData;
                    if (resbuf == null)
                        continue;
                    writer.WriteStartElement("resbuf");
                    TypedValue[] tvs = resbuf.AsArray();
                    foreach (TypedValue tv in tvs)
                    {
                        writer.WriteStartElement("xdata");
                        writer.WriteAttributeString("code", tv.TypeCode.ToString());
                        writer.WriteAttributeString("value", tv.Value.ToString());
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                    cnt++;
                }
                tr.Commit();
            }
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            writer.Close();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filename);
            List<ResultBuffer> lst = new List<ResultBuffer>(cnt);
            foreach (XmlNode xdatas in xmlDoc.ChildNodes[1].ChildNodes)
            {
                ResultBuffer resbuf = new ResultBuffer();
                foreach (XmlNode data in xdatas.ChildNodes)
                {
                    XmlAttributeCollection atts = data.Attributes;
                    short code = Convert.ToInt16(atts["code"].Value);
                    resbuf.Add(new TypedValue(
                        code,
                        GetValue(code, atts["value"].Value)));
                }
                lst.Add(resbuf);
            }
            DateTime t1 = DateTime.Now;
            TimeSpan ts = t1 - t0;
            ed.WriteMessage("\nEllapsed milliseconds: " + ts.TotalMilliseconds.ToString());
        }

        private object GetValue(short code, string p)
        {
            switch (code)
            {
                case 1010:
                    return StringToPoint(p);
                case 1040:
                    return Convert.ToDouble(p);
                case 1070:
                    return Convert.ToInt32(p);
                default:
                    return p;
            }
        }

        private Point3d StringToPoint(string p)
        {
            int pos0 = 1;
            int pos1 = p.IndexOf(',');
            double x = Convert.ToDouble(p.Substring(1, pos1 - pos0));
            pos0 = pos1 + 1;
            pos1 = p.IndexOf(',', pos0);
            double y = Convert.ToDouble(p.Substring(pos0, pos1 - pos0));
            pos0 = pos1 + 1;
            pos1 = p.IndexOf(')', pos0);
            double z = Convert.ToDouble(p.Substring(pos0, pos1 - pos0));
            return new Point3d(x, y, z);
        }
    }
}

I wrote a little one in LISP, it's nearly as fast...

Code: [Select]
(defun c:gileLsp (/ t0 t1 n ss file line lst)
  (vl-load-com)
  (setq t0 (getvar 'millisecs))
  (if (setq ss (ssget "_X" '((-3 ("MYXDATA")))))
    (progn
      (setq n 0
            file (open "C:\\SerializeChallenge.txt" "w")
            )
      (while (setq ent (ssname ss n))
        (write-line (vl-prin1-to-string (assoc -3 (entget ent '("MYXDATA")))) file)
        (setq n (1+ n))
      )
      (close file)
      (setq file (open "C:\\SerializeChallenge.txt" "r"))
      (while (setq line (read-line file))
        (setq lst (cons (read line) lst))
      )
      (reverse lst)
      (close file)
    )
  )
  (setq t1 (getvar 'millisecs))
  (princ (strcat "\n" (itoa n) " objects collected in " (itoa (- t1 t0))" milliseconds"))
  (princ)
)

I thaught my routine was slow, there're not very fast, but it seems to be my computer which is slower than yours...

Quote
Commande: gileCs
Ellapsed milliseconds: 6562.5
Commande: gileCs
Ellapsed milliseconds: 6593.75
Commande: gileCs
Ellapsed milliseconds: 6421.875

Commande: GILELSP
100000 objects collected in 8672 milliseconds
Commande: GILELSP
100000 objects collected in 8703 milliseconds
Commande: GILELSP
100000 objects collected in 8672 milliseconds

Commande: KDUB_DOIT
 100000 Objects Collected in : 14890 Milliseconds.
Commande: KDUB_DOIT
 100000 Objects Collected in : 15110 Milliseconds.
Commande: KDUB_DOIT
 100000 Objects Collected in : 15047 Milliseconds.
« Last Edit: January 22, 2010, 05:04:16 PM by gile »
Speaking English as a French Frog

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: -+{ Challenge }+- Serialize Xdata
« Reply #18 on: January 22, 2010, 06:46:42 PM »
gile

re : (defun c:gileLsp .......

Yes, using a linear approach with minimum variables and writing to the open file as each point is captured
is a lot faster than the modular approach I used. 

Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #19 on: January 22, 2010, 07:44:41 PM »
HuH! I expected .NET to be much faster  :-o  :-o  :-o

Code: [Select]
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices;

[assembly: CommandClass(typeof(NetSerialize.Commands))]

namespace NetSerialize
{

  public class Commands
  {

    [Serializable]
    public class pnt3d
    {
      double x, y, z;
      public pnt3d(Point3d p)
      {
        x = p.X;
        y = p.Y;
        y = p.Z;
      }
      public double Z
      {
        get { return z; }
        set { z = value; }
      }
      public double Y
      {
        get { return y; }
        set { y = value; }
      }
      public double X
      {
        get { return x; }
        set { x = value; }
      }
    }

    [CommandMethod("doit")]
    static public void doit()
    {
      Stopwatch stopWatch = new Stopwatch();
      stopWatch.Start();

      Database db = HostApplicationServices.WorkingDatabase;
      string filename = "C:\\SerializeChallenge.dat";

      List<KeyValuePair<int, Object>>
          kvList = new List<KeyValuePair<int, object>>();

      using (Transaction tr = db.TransactionManager.StartTransaction())
      {
        BlockTable bt = (BlockTable)
          tr.GetObject(db.BlockTableId, OpenMode.ForRead);
        BlockTableRecord btr =(BlockTableRecord)
          tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);

        foreach (ObjectId id in btr)
        {
          Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead, false);
          ResultBuffer resbuf = ent.XData;
          if (resbuf == null)
            continue;

          foreach (TypedValue item in resbuf)
          {
            if((int)item.TypeCode == 1010)
            {
              pnt3d p = new pnt3d((Point3d)item.Value);
              kvList.Add(new KeyValuePair<int, object>
                     ((int)item.TypeCode, p));
            }
            else
            {
              kvList.Add(new KeyValuePair<int, object>
                     ((int)item.TypeCode, item.Value));
            }
          }

        }
        tr.Commit();
      }
      dome(kvList, filename);
      stopWatch.Stop();
      TimeSpan ts = stopWatch.Elapsed;

      AcAp.Application.DocumentManager.
         MdiActiveDocument.Editor.WriteMessage
          ("\n{0} Milliseconds", ts.TotalMilliseconds);
    }

    [CommandMethod("undoit")]
    static public void undoit()
    {
      Stopwatch stopWatch = new Stopwatch();
      stopWatch.Start();

      string filename = "C:\\SerializeChallenge.dat";
      List<KeyValuePair<int, Object>> list = undome(filename);

      stopWatch.Stop();
      TimeSpan ts = stopWatch.Elapsed;

      AcAp.Application.DocumentManager.
         MdiActiveDocument.Editor.WriteMessage
           ("\n{0} Milliseconds", ts.TotalMilliseconds);
    }

    static public void dome(List<KeyValuePair<int, Object>> kvList,
                            string filename)
    {
      Stream stream = new FileStream(filename, FileMode.Create);
      try
      {
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, kvList);
      }
      catch (System.Exception ex)
      {
        AcAp.Application.DocumentManager.
          MdiActiveDocument.Editor.
            WriteMessage("crash {0}",ex.Message);
      }
      finally
      {
        stream.Close();
      }
    }


    static public List<KeyValuePair<int, Object>> undome(string filename)
    {
      List<KeyValuePair<int, Object>> kvList = null;
      Stream stream = null;
      try
      {
        stream = new FileStream(filename, FileMode.Open);
        IFormatter formatter = new BinaryFormatter();
        kvList =(List<KeyValuePair<int, Object>>)
                            formatter.Deserialize(stream);
      }
      catch (System.Exception ex)
      {
        AcAp.Application.DocumentManager.
          MdiActiveDocument.Editor.
           WriteMessage("crash {0}", ex.Message);
      }
      finally
      {
        stream.Close();
      }
      return kvList;
    }
  }
}
« Last Edit: January 22, 2010, 07:49:02 PM by Daniel »

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #20 on: January 22, 2010, 09:33:13 PM »
A little more work for the C++ version, it's a tad faster  :evil:

CTypedValue.h
Code: [Select]
class CTypedValue : public CObject
{
public:
  union __declspec(novtable) Value
  {
    inline Value(){ this->setNull(); }
    inline void setNull(){memset(this,0,sizeof(Value));}
    unsigned char vChar;
    unsigned char vHandle[8];
    short         vShort;
    long          vLong;
    long          vEname[2];
    __int64       vInt64;
    double        vDouble;
    double        vPoint2d[2];
    double        vPoint3d[3];
    unsigned char vCharArray[24];
  } _value;

  CString vString;
  short _dfxType;

protected:
  DECLARE_SERIAL(CTypedValue)

public:
  enum ValueType {TVNull, TVChar, TVShort, TVLong, TVString, TVInt64,
                  TVEName,TVDouble, TVPoint2d, TVPoint3d, TVByteArray,
                  TVLispSym,TVHandle}_valueType;

public:
  CTypedValue( void );
  CTypedValue( const resbuf *src );
  CTypedValue( const CTypedValue& src );
  virtual ~CTypedValue( void );
  CTypedValue& operator=( const CTypedValue& src );

  bool operator == ( const CTypedValue& src ) const;
  bool operator != ( const CTypedValue& src ) const;
  bool Equals( const CTypedValue& src ) const;

  virtual void Serialize( CArchive &ar );
  resbuf* ToResbuf( void ) const;
};

CTypedValue.cpp
Code: [Select]
#include "StdAfx.h"
#include "TypedValue.h"


IMPLEMENT_SERIAL( CTypedValue, CObject, VERSIONABLE_SCHEMA|1)

CTypedValue::CTypedValue(void)
: _value(), _valueType(TVNull) , _dfxType(0){}

CTypedValue::CTypedValue( const resbuf *buf )
: _value(), _valueType(TVNull) , _dfxType(buf->restype)
{
  if(buf != NULL)
  {
    if(buf->restype > 5000)
    {
      switch (buf->restype)
      {
      case RTSTR:{
          _valueType = TVString;
          vString = buf->resval.rstring;
          break;
        }
      case RTSHORT:{
          _valueType = TVShort;
          _value.vShort = buf->resval.rint;
          break;
        }
      case RTLONG:{
          _valueType = TVLong;
          _value.vLong = buf->resval.rlong;
        }
      case RTREAL:{
          _valueType = TVDouble;
          _value.vDouble= buf->resval.rreal;
          break;
        }
      case RTENAME:{
          _valueType = TVEName;
          memcpy( _value.vEname,buf->resval.rlname,sizeof(_value.vEname));
          break;
        }
      case RTPOINT:{
          _valueType = TVPoint2d;
          memcpy( _value.vPoint3d,buf->resval.rpoint,sizeof(_value.vPoint3d));
          break;
        }
      case RT3DPOINT:{
          _valueType = TVPoint3d;
          memcpy( _value.vPoint3d,buf->resval.rpoint,sizeof(_value.vPoint3d));
          break;
        }
      default:{
          _valueType = TVLispSym;
        }
      }
    }
    else if(buf->restype < 5000)
    {
      short type = acdbGroupCodeToType(buf->restype);
      switch (type)
      {
      case kDwgText:{
          _valueType = TVString;
          vString = buf->resval.rstring;
          break;
        }
      case kDwgInt8:{
          _valueType = TVChar;
          _value.vShort = buf->resval.rint;
          break;
        }
      case kDwgInt16:{
          _valueType = TVShort;
          _value.vShort = buf->resval.rint;
          break;
        }
      case AcDb::kDwgInt32:{
          _valueType = TVLong;
          _value.vLong = buf->resval.rlong;
          break;
        }
      case AcDb::kDwgReal:{
          _valueType = TVDouble;
          _value.vDouble= buf->resval.rreal;
          break;
        }
      case kDwgHandle:{
          _valueType = TVHandle;
          memcpy(_value.vHandle, buf->resval.ihandle, sizeof(_value.vHandle));
          break;
        }
      case kDwgHardOwnershipId:
      case kDwgSoftOwnershipId:
      case kDwgHardPointerId:
      case kDwgSoftPointerId:{
          _valueType = TVEName;
           memcpy( _value.vEname,buf->resval.rlname,sizeof(_value.vEname));
          break;
        }
      case kDwg3Real:{
          _valueType = TVPoint3d;
          memcpy( _value.vPoint3d,buf->resval.rpoint,sizeof(_value.vPoint3d));
          break;
        }
      }
    }
  }
}

CTypedValue::CTypedValue( const CTypedValue& src )
: _value(), _valueType(TVNull) ,  _dfxType(0){}

CTypedValue::~CTypedValue(void)
{
  _value.setNull();
}

CTypedValue& CTypedValue::operator=( const CTypedValue& src )
{
  if(this != &src)
  {
    memcpy(&_value,&src._value,sizeof(src._value));
    _valueType = src._valueType;
    _dfxType = src._dfxType;
    if(_valueType == TVString)
    {
      this->vString =  src.vString;
    }
  }
  return *this;
}

bool CTypedValue::operator==( const CTypedValue& src ) const
{
  return this->Equals(src);
}

bool CTypedValue::operator!=( const CTypedValue& src ) const
{
  return !this->Equals(src);
}

bool CTypedValue::Equals( const CTypedValue& src ) const
{
  if(_valueType == TVString && src._valueType == TVString)
  {
    return this->vString.Compare(src.vString) == 0;
  }
  else if (memcmp(&_value, &src._value, sizeof(CTypedValue::Value)) == 0)
  {
    return true;
  }
  return false;
}

void CTypedValue::Serialize( CArchive &ar )
{
  CObject::Serialize( ar );

  if (ar.IsStoring())
  {
    for(size_t i = 0 ; i < sizeof(_value) ; i++)
    {
      ar << _value.vCharArray[i];
    }
    ar << vString;
    ar << (int)_valueType;
    ar << _dfxType;
  }
  else
  {
    for(size_t i = 0 ; i < sizeof(_value) ; i++)
    {
      ar >> _value.vCharArray[i];
    }
    ar >> vString;
    ar >> (int&)_valueType;
    ar >> _dfxType;;
  }
}

resbuf* CTypedValue::ToResbuf( void ) const
{
  resbuf *pBuf = NULL;
  if(_valueType == TVString)
  {
    pBuf = acutBuildList(_dfxType,vString,0);
  }
  else
  {
    pBuf = acutNewRb(_dfxType);//24 bytes
    memcmp(&pBuf->resval,&_value,sizeof(pBuf->resval.rpoint));
  }
  return pBuf;
}

CTypedValueArray.h
Code: [Select]
#pragma once
#include "afxtempl.h"
#include "TypedValue.h"

typedef  CArray<CTypedValue,CTypedValue&> Base_CTypedValueArray;


class CTypedValueArray : public Base_CTypedValueArray
{
public:
  CTypedValueArray(void);
  void AppendResbuf(const resbuf *pRb);
  virtual ~CTypedValueArray(void);
  virtual void Serialize(CArchive& ar);
  void SerializeElements (CArchive& ar, CTypedValue* pCTypedValue, INT_PTR nCount);
  resbuf* ToRbChain(void) const;
};

CTypedValueArray.cpp
Code: [Select]
#include "StdAfx.h"
#include "TypedValueArray.h"

CTypedValueArray::CTypedValueArray( void ) : Base_CTypedValueArray(){}

CTypedValueArray::~CTypedValueArray( void ){}

void CTypedValueArray::AppendResbuf( const resbuf *pRb )
{
  for(const resbuf* tmp = pRb;tmp!=NULL;tmp = tmp->rbnext)
  {
    this->Add(CTypedValue(tmp));
  }
}

void CTypedValueArray::Serialize( CArchive& ar )
{
  ASSERT_VALID(this);

  CObject::Serialize(ar);
  if (ar.IsStoring())
  {
    ar.WriteCount(m_nSize);
  }
  else
  {
    DWORD_PTR nOldSize = ar.ReadCount();
    SetSize(nOldSize, -1);
  }
  SerializeElements(ar, m_pData, m_nSize);
}

void CTypedValueArray::SerializeElements( CArchive& ar, CTypedValue* pCTypedValue, INT_PTR nCount )
{
  ENSURE(nCount == 0 || pCTypedValue != NULL);
  ASSERT(nCount == 0 || AfxIsValidAddress(pCTypedValue, (size_t)nCount * sizeof(CTypedValue)));

  for (INT_PTR i = 0; i < nCount; i++, pCTypedValue++)
    pCTypedValue->Serialize(ar);
}

resbuf* CTypedValueArray::ToRbChain( void ) const
{
  if(this->GetCount() == 0)
    return NULL;

  resbuf* pHead = this->GetAt(0).ToResbuf();
  resbuf* pTail = pHead;
  for(size_t i=1;i<this->GetCount();i++)
  {
   pTail = pTail->rbnext = this->GetAt(i).ToResbuf();
  }
  return pHead;
}


arx
Code: [Select]
static void ArxSerialize_doit(void)
  {
    LARGE_INTEGER freq,start,end; 
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start);

    CTypedValueArray arr;
    resbuf *pRb = acutNewRb(RTVOID);
    size_t len = GetAllXdata(pRb);

    arr.SetSize(len);
    fillarray(arr,pRb->rbnext);
    acutRelRb(pRb);

    CFile fHandles;
    fHandles.Open(_T("c:\\xdata.dat"),
      CFile::modeCreate | CFile::modeWrite |  CFile::typeBinary );
    CArchive ar(&fHandles, CArchive::store);
    arr.Serialize(ar);
    ar.Close();
    fHandles.Close();

    acutPrintf(_T("\nSerialized Elements %ld"),arr.GetCount());
    QueryPerformanceCounter( &end );
    acutPrintf(_T("\n%g"),(double)
      (end.QuadPart-start.QuadPart)/freq.QuadPart );
  }


  static void ArxSerialize_undoit(void)
  {
    LARGE_INTEGER freq,start,end; 
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start);

    CTypedValueArray arr;
    CFile fHandles;
    fHandles.Open(_T("c:\\xdata.dat"),  CFile::modeRead |  CFile::typeBinary);
    CArchive ar(&fHandles, CArchive::load);
    arr.Serialize(ar);
    ar.Close();
    fHandles.Close();

    acutPrintf(_T("\nDeserialized Elements %ld"),arr.GetCount());
    QueryPerformanceCounter( &end );
    acutPrintf(_T("\n%g"),(double)
      (end.QuadPart-start.QuadPart)/freq.QuadPart );
  }

  static size_t GetAllXdata( resbuf* pRb )
  {
    size_t cnt= 0;
    resbuf *pTail = pRb;
    AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
    AcDbBlockTableRecordPointer pCurBtr(pDb->currentSpaceId(),AcDb::kForRead);
    if(pCurBtr.openStatus() == Acad::eOk)
    {
      AcDbBlockTableRecordIterator *pIter = NULL;
      if(pCurBtr->newIterator(pIter) == Acad::eOk)
      {
        AcDbObjectId id;
        for(pIter->start();!pIter->done();pIter->step())
        {
          pIter->getEntityId(id);
          AcDbEntityPointer pEnt(id,AcDb::kForRead);
          if(pEnt.openStatus() == eOk)
          {
            for(resbuf* tmp=pEnt->xData(_T("myxdata"));tmp!=NULL;tmp=tmp->rbnext)
            {
              pTail = pTail->rbnext = tmp;
              cnt++;
            }
          }
        }
      }
      delete pIter;
    }
    return cnt;
  }

  static void fillarray(CTypedValueArray &arr,const resbuf *pRb)
  {
    CTypedValue* pPt = (CTypedValue*) arr.GetData();
    for(const resbuf* tmp = pRb;tmp!=NULL;tmp = tmp->rbnext)
    {
      *pPt = CTypedValue(tmp);
      pPt++;
    }
  }
} ;


Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: -+{ Challenge }+- Serialize Xdata
« Reply #21 on: January 22, 2010, 09:39:57 PM »
A little more work for the C++ version, it's a tad faster  :evil:


 :-D

You had to make the point count 500,000 instead of 100,000 just to get a time reading, yes ?  :wink:
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #22 on: January 22, 2010, 10:04:25 PM »
oops sorry, that number is the number of elements in my array, just to test what went out, was what I got back in. 100,000 * (1appname + 4xdata elements).
I thought my .NET version would be closer in performance, I must have done something wrong.  :|
Lisp performed impressively

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: -+{ Challenge }+- Serialize Xdata
« Reply #23 on: January 22, 2010, 10:07:29 PM »

Lisp performed impressively


Generally does  : ) , ... pity it has been treated like a second class citizen.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

gile

  • Water Moccasin
  • Posts: 2233
  • Marseille, France
Re: -+{ Challenge }+- Serialize Xdata
« Reply #24 on: January 23, 2010, 02:46:11 AM »
Hi,

My second C# routine (using serialized classes) is quite closed to Daniel's one.

On my computer, they both crashes the same way on deserialization (can't find the assembly):
Quote
Commande: test2
Erreur: Impossible de trouver l'assembly 'SerializeChallenge, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'.
Ellapsed milliseconds: 7843.75

Commande: doit
5922.0574 Milliseconds

Commande: undoit
crash Impossible de trouver l'assembly 'SerializeChallenge, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'.
11925.9626 Milliseconds

Any idea ?

Code: [Select]
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace SerializeChallenge
{
    public class Class2
    {
        [CommandMethod("Test2")]
        public void Test2()
        {
            DateTime t0 = DateTime.Now;
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            string filename = "C:\\SerializeChallenge.dat";
            List<SerializableResultBuffer> lst = new List<SerializableResultBuffer>();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr =
                    (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                foreach (ObjectId id in btr)
                {
                    Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead, false);
                    ResultBuffer resbuf = ent.XData;
                    if (resbuf == null)
                        continue;
                    lst.Add(new SerializableResultBuffer(resbuf));
                }
                tr.Commit();
            }
            FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
            try
            {
            BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(fs, lst);
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\nErreur: " + ex.Message);
            }
            finally
            {
                fs.Close();
            }

            fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
            try
            {
                BinaryFormatter formatter = new BinaryFormatter();
                lst = (List<SerializableResultBuffer>)formatter.Deserialize(fs);
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage("\nErreur: " + ex.Message);
            }
            finally
            {
                fs.Close();
            }
            foreach (SerializableResultBuffer srb in lst)
            {
                ResultBuffer resbuf = new ResultBuffer();
                foreach (SerializableTypedValue stv in srb.STypedValues)
                {
                    int code = stv.Code;
                    if (code == 1010)
                    {
                        SerializablePoint3d spt = (SerializablePoint3d)stv.Value;
                        resbuf.Add(new TypedValue(code, new Point3d(spt.X, spt.Y, spt.Z)));
                    }
                    else
                        resbuf.Add(new TypedValue(code, stv.Value));
                }
            }
            DateTime t1 = DateTime.Now;
            TimeSpan ts = t1 - t0;
            ed.WriteMessage("\nEllapsed milliseconds: " + ts.TotalMilliseconds.ToString());
        }
    }

    [Serializable]
    public class SerializableResultBuffer
    {
        private List<SerializableTypedValue> stv = new List<SerializableTypedValue>();

        public SerializableResultBuffer(ResultBuffer resbuf)
        {
            TypedValue[] tvs = resbuf.AsArray();
            foreach (TypedValue tv in tvs)
            {
                stv.Add(new SerializableTypedValue(tv));
            }
        }

        public List<SerializableTypedValue> STypedValues
        {
            get { return stv; }
        }
    }

    [Serializable]
    public class SerializableTypedValue
    {
        private int code;
        private object value;

        public SerializableTypedValue(TypedValue tv)
        {
            code = (int)tv.TypeCode;
            value = (code == 1010) ?
                new SerializablePoint3d((Point3d)tv.Value) :
                tv.Value;
        }

        public int Code
        {
            get { return code; }
        }

        public object Value
        {
            get { return value; }
        }
    }

    [Serializable]
    public class SerializablePoint3d
    {
        private double x;
        private double y;
        private double z;

        public SerializablePoint3d(Point3d pt)
        {
            x = pt.X;
            y = pt.Y;
            z = pt.Z;
        }

        public double X
        {
            get { return x; }
        }

        public double Y
        {
            get { return y; }
        }

        public double Z
        {
            get { return z; }
        }
    }
}
Speaking English as a French Frog

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #25 on: January 23, 2010, 02:53:03 AM »
Nice work! I needed to netload the DLL from the AutoCAD folder to avoid the error, I think it's some security measure.

gile

  • Water Moccasin
  • Posts: 2233
  • Marseille, France
Re: -+{ Challenge }+- Serialize Xdata
« Reply #26 on: January 23, 2010, 03:30:40 AM »
Quote
Nice work!
Thanks !
I'm proud, it was the first time I used serialization classes and methods.
I thaught I was wrong because of this error. Thanks to fix it.

Anyway this seems to be a slower way than using a XML file. Re-building a ResusultBuffer from a Serializable object looks time expansive.
Speaking English as a French Frog

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: -+{ Challenge }+- Serialize Xdata
« Reply #27 on: January 23, 2010, 10:00:35 PM »

How fast can you doit?


about 3 months I think :)


after spending half an hour reviewing the C++ code
I'll change that to

"about 13 months"
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate to theSwamp<--

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #28 on: January 23, 2010, 10:17:56 PM »
Nah it's not so bad using CArchive, have a look at this basic 'Serializable' class

Code: [Select]
// derive from
class CNamedHandle: public CObject
{
private:
  CString m_name;
  AcDbHandle m_handle;

protected:
  DECLARE_SERIAL(CNamedHandle)//<------------ need this

public:
  CNamedHandle( void );
  CNamedHandle( const CNamedHandle &src );
  CNamedHandle( const CString &dwgName,const AcDbHandle &handle );
  virtual ~CNamedHandle( void );

  CNamedHandle& operator=( const CNamedHandle& rhs );
  bool operator==( const CNamedHandle& rhs ) const;
  bool operator!=( const CNamedHandle& rhs ) const;

  virtual bool    Equals( const CNamedHandle& rhs ) const;
  virtual void    Serialize( CArchive &ar );//<------------ need this
  virtual CString ToString( void ) const;
  AcDbHandle      getHandle( void ) const;
  void            setHandle(const AcDbHandle &val);
  CString         getDwgName( void ) const;
  void            setDwgName(const CString &val);

  __declspec( property(get=getHandle,put=setHandle) )AcDbHandle Handle;
  __declspec( property(get=getDwgName,put=setDwgName) )CString DwgName;
};

Code: [Select]
#include "StdAfx.h"
#include "NamedHandle.h"

//***** need this ********//
IMPLEMENT_SERIAL( CNamedHandle, CObject, VERSIONABLE_SCHEMA|1)

CNamedHandle::CNamedHandle(void)
: m_name(),m_handle(){}

CNamedHandle::CNamedHandle( const CNamedHandle &src )
: m_name(),m_handle(){}

CNamedHandle::CNamedHandle( const CString &dwgName, const AcDbHandle &handle )
: m_name(dwgName),m_handle(handle){}

CNamedHandle::~CNamedHandle(void){}

CNamedHandle& CNamedHandle::operator=( const CNamedHandle& rhs )
{
  if(this != &rhs)
  {
    m_name = rhs.m_name;
    m_handle = rhs.m_handle;
  }
  return *this;
}

bool CNamedHandle::operator==( const CNamedHandle& rhs ) const
{
  return Equals(rhs);
}

bool CNamedHandle::operator!=( const CNamedHandle& rhs ) const
{
  return !Equals(rhs);
}

bool CNamedHandle::Equals( const CNamedHandle& rhs ) const
{
  return (this->m_name ==  rhs.m_name &&
    this->m_handle ==  rhs.m_handle);
}


void CNamedHandle::Serialize( CArchive &ar ) // <------------ Need this
{
  CObject::Serialize( ar );

  // data out
  if (ar.IsStoring())
  {
    ar << m_name;
    ar << (__int64)m_handle;
  }
  //data in
  else
  {
    ar >> m_name;
    ar >> (__int64&)m_handle;
  }
}

CString CNamedHandle::ToString( void )const
{
  CString str;
  str.Format(_T("(%s, %I64d)"),m_name,(__int64)m_handle);
  return str;
}

AcDbHandle CNamedHandle::getHandle( void ) const
{
  return m_handle;
}

void CNamedHandle::setHandle( const AcDbHandle &val )
{
  m_handle = val;
}

CString CNamedHandle::getDwgName( void ) const
{
  return m_name;
}

void CNamedHandle::setDwgName( const CString &val )
{
  m_name = val;
}

then I just need to call CNamedHandle::Serialize done !

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: -+{ Challenge }+- Serialize Xdata
« Reply #29 on: January 23, 2010, 10:24:43 PM »
you can then build a Seralizable CArray for your object.

Code: [Select]
#pragma once
#include "afxtempl.h"
#include "NamedHandle.h"

typedef CArray <CNamedHandle, CNamedHandle&> Base_CNamedHandleArray;

class CNamedHandleArray : public Base_CNamedHandleArray
{
public:
  CNamedHandleArray(void);
  virtual ~CNamedHandleArray(void);

public:
  // we can override Serialize
  virtual void Serialize(CArchive& ar);
  void SerializeElements (CArchive& ar, CNamedHandle* pCNamedHandle, INT_PTR nCount);
};

Code: [Select]
#include "StdAfx.h"
#include "NamedHandleArray.h"

CNamedHandleArray::CNamedHandleArray(void)
: Base_CNamedHandleArray(){}

CNamedHandleArray::~CNamedHandleArray(void){}

void CNamedHandleArray::Serialize( CArchive& ar )
{
  ASSERT_VALID(this);

  CObject::Serialize(ar);
  if (ar.IsStoring())
  {
    ar.WriteCount(m_nSize);
  }
  else
  {
    DWORD_PTR nOldSize = ar.ReadCount();
    SetSize(nOldSize, -1);
  }
  SerializeElements(ar, m_pData, m_nSize);
}

//serialize each element
void CNamedHandleArray::SerializeElements( CArchive& ar,
                                           CNamedHandle* pCNamedHandle,
                                           INT_PTR nCount )
{
  for (INT_PTR i = 0; i < nCount; i++, pCNamedHandle++)
  {
    pCNamedHandle->Serialize(ar);
  }
}


then call CNamedHandleArray::Serialize  :laugh: