Author Topic: Generic Dictionary  (Read 14890 times)

0 Members and 1 Guest are viewing this topic.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
Re: Generic Dictionary
« Reply #15 on: July 22, 2011, 08:28:53 AM »
If your Dictionary entries values are list of string arrays, you have to go on level deeper in the DBDictionary because, as you ca see in the samples, the Xrecord.Value is a ResulBuffer and a TypedValue cannot contain a string array.

So, you have to add first DBDictionary (as NOD child or extension dictionary of a DBObject).
In this first dictionary, add one DBDictionary per List (entry of the source Dictionary).
In each of these DBDictionaries an Xrecord for each string array in the List (with incremented names for example).
And fill the Xrecord.Value with the string contained in the array.
Speaking English as a French Frog

kaefer

  • Guest
Re: Generic Dictionary
« Reply #16 on: July 22, 2011, 09:52:51 AM »
If your Dictionary entries values are list of string arrays, you have to go on level deeper in the DBDictionary because, as you ca see in the samples, the Xrecord.Value is a ResulBuffer and a TypedValue cannot contain a string array.

Now, that's much too complicated for me. And besides, if the 'customer' doesn't have their specifications nailed down and their goalposts are in danger of shifting, there's always another joker up our sleeves: serialization. Too bad this won't work with Xml; but the BinaryFormatter is still good enough:

Code: [Select]
let out (x : 'a) =
    let formatter = new Formatters.Binary.BinaryFormatter()
    use ms = new System.IO.MemoryStream()
    formatter.Serialize(ms, x)
    System.Convert.ToBase64String(
        ms.GetBuffer(),
        System.Base64FormattingOptions.InsertLineBreaks )
   
let in' txt =
    let ms = new System.IO.MemoryStream(System.Convert.FromBase64String txt)
    let formatter = new Formatters.Binary.BinaryFormatter()
    try
        formatter.Deserialize ms :?> _
    finally
        ms.Dispose()
   
let xToXrecord x xrName =
    let db = HostApplicationServices.WorkingDatabase
    use tr = db.TransactionManager.StartTransaction()
   
    let nod = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite) :?> DBDictionary
    let tvs =
        x |> out |> fun s ->
            s.Split([|'\r'; '\n'|], System.StringSplitOptions.RemoveEmptyEntries)
        |> Array.map (fun s ->
            new TypedValue(int DxfCode.Text, s) )
    let rb = new ResultBuffer(tvs)
    let xr = new Xrecord(Data = rb)
    nod.SetAt(xrName, xr) |> ignore
    tr.AddNewlyCreatedDBObject(xr, true)

    tr.Commit()

let xrecordToX xrName =
    let db = HostApplicationServices.WorkingDatabase
    use tr = db.TransactionManager.StartTransaction()

    let nod = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead) :?> DBDictionary
    let xr = tr.GetObject(nod.GetAt xrName, OpenMode.ForRead) :?> Xrecord
    let sb = new System.Text.StringBuilder()
    for tv in xr.Data do
        if tv.TypeCode = int16 DxfCode.Text then
            sb.Append tv.Value |> ignore
    sb.ToString() |> in'

[<CommandMethod "TEST">]
let test() =
    let dict = new Dictionary<string, List<string>>();
    dict.Add("foo", new List<string>[| "a"; "b"; "c" |])
    dict.Add("bar", new List<string>[| "x"; "y"; "z" |])
    dict.Add("baz", new List<string>[| "this"; "is"; "a"; "test" |])
    xToXrecord dict "StringArraysDictionary"

[<CommandMethod "TESTBACK">]
let testBack() =
    let ed = acadApp.DocumentManager.MdiActiveDocument.Editor
    try
        let dict : Dictionary<string, List<string>> =
            xrecordToX "StringArraysDictionary"
        for KeyValue(k, v) in dict do
            ed.WriteMessage("\n{0} = ", k)
            for s in v do
                ed.WriteMessage("{0} ", s)
    with _ ->
        ed.WriteMessage "\nThe 'StringArraysDictionary' dictionary can't be found. "


cadpro

  • Guest
Re: Generic Dictionary
« Reply #17 on: July 24, 2011, 09:27:26 PM »
Hi,

This code looks promising. Thanks kaefer. But could someone please convert this code for me to C# or VB.NET?

Thanks

kaefer

  • Guest
Re: Generic Dictionary
« Reply #18 on: July 25, 2011, 09:53:50 AM »
But could someone please convert this code for me to C# or VB.NET?

I'm sorry cadpro, I can't do that.

But you can have a look at my latest, new and improved version, all-singing, all-dancing; which uses DxfCode.BinaryChunk instead of text, and as icing on the top gzip compression too. That last feature is a bear, there's no seek and no direct buffer access on a compressed stream, so there are lots of MemoryStreams around and I'm still not sure if there's a better way to do it...

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

using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace SerializedObjectGZippedXrecord
{
    public class Commands
    {
        Database db;
        Editor ed;
        public Commands(){
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            db = doc.Database;
            ed = doc.Editor;
        }
           
        [CommandMethod("TestGz")]
        public void TestGz()
        {
            Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
            dict.Add("foo", new List<string> { "a", "b", "c" });
            dict.Add("bar", new List<string> { "x", "y", "z" });
            dict.Add("baz", new List<string> { "this", "is", "a", "test" });

            XToXrecord(dict, "StringArraysDictionary");
        }

        private void XToXrecord(object o, string key)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (MemoryStream ins = new MemoryStream())
            using (MemoryStream outs = new MemoryStream())
            {
                DBDictionary nod =
                    (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(ins, o);
                byte[] ibuf = ins.ToArray();

                using (GZipStream gz = new GZipStream(outs, CompressionMode.Compress))
                    gz.Write(ibuf, 0, ibuf.Length);
                byte[] obuf = outs.ToArray();

                ResultBuffer rb = new ResultBuffer();
                const int chunkSize = 127;
                int bytesConsumed = 0;
                while (bytesConsumed < obuf.Length)
                {
                    int bytesToRead = obuf.Length - bytesConsumed;
                    int count = bytesToRead < chunkSize ? bytesToRead : chunkSize;
                    byte[] chunk = new byte[count];
                    Array.Copy(obuf, bytesConsumed, chunk, 0, count);
                    rb.Add(new TypedValue((int) DxfCode.BinaryChunk, chunk));
                    bytesConsumed += count;
                }
                Xrecord xrec = new Xrecord();
                xrec.Data = rb;
               
                nod.SetAt(key, xrec);
                tr.AddNewlyCreatedDBObject(xrec, true);

                tr.Commit();
            }
        }

        [CommandMethod("TestGzBack")]
        public void TestGzBack()
        {
            var dict = XrecordToX("StringArraysDictionary") as Dictionary<string, List<string>>;
            if (dict == null)
            {
                ed.WriteMessage("\nThe 'StringArraysDictionary' dictionary can't be found.");
                return;
            }
            foreach (KeyValuePair<string, List<string>> pair in dict)
            {
                string datas = string.Empty;
                foreach (string s in pair.Value)
                {
                    datas += " " + s;
                }
                ed.WriteMessage("\n{0} ={1}", pair.Key, datas);
            }
        }

        private object XrecordToX(string key)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (MemoryStream ins = new MemoryStream())
            using (MemoryStream outs = new MemoryStream())
            {
                DBDictionary nod =
                    (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                try
                {
                    Xrecord xrec = (Xrecord)tr.GetObject(nod.GetAt(key), OpenMode.ForRead);
                    foreach(TypedValue tv in xrec.Data){
                        if (tv.TypeCode == (int)DxfCode.BinaryChunk)
                        {
                            byte[] buf = (byte[])tv.Value;
                            ins.Write(buf, 0, buf.Length);
                        }
                    }
                    ins.Position = 0;
                    using (GZipStream gz = new GZipStream(ins, CompressionMode.Decompress))
                        gz.CopyTo(outs);

                    outs.Position = 0;
                    BinaryFormatter formatter = new BinaryFormatter();
                    return (formatter.Deserialize(outs));
                }
                catch
                {
                    return null;
                }
            }
        }
    }
    public static class Extensions
    {
        public static void CopyTo(this Stream ins, Stream outs)
        {
            const int bufSize = 4096;
            byte[] buf = new byte[bufSize];
            int readBytes;
            do
            {
                readBytes = ins.Read(buf, 0, buf.Length);
                if (readBytes > 0)
                    outs.Write(buf, 0, readBytes);
            }
            while (readBytes == bufSize);
        }
    }
}

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Generic Dictionary
« Reply #19 on: July 25, 2011, 02:12:52 PM »
I see you trying to use a Dictionary<string, List<string[]>>-----I missed the extra parentheses

kaefer's solution is better but here is one hard-coded and doing what gile mentioned in previous post.

This is a example and has it pit falls but just for example to show you one way of nesting it.
So you need to modify it.

This made me go cross-eyed using Dictionary<string, List<string[]>>



Commands

Code: [Select]
  const string DIC_NAME = "HpadDictionary";       
        [CommandMethod("XrecordDictionaryAdd")]
        public void XrecordDictionaryAdd()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            using (Transaction trx = db.TransactionManager.StartTransaction())
            {

                Dictionary<string, List<string[]>> dictionary = new Dictionary<string, List<string[]>>();
                string[] valsA1 = { "A1-1", "A1-2" };
                string[] valsA2 = { "A2-1", "A2-2" };
                dictionary.Add("A", new List<string[]> {valsA1, valsA2});
                string[] valsB1 = { "B1-1", "B1-2" };
                string[] valsB2 = { "B2-1", "B2-2" };
                dictionary.Add("B", new List<string[]> { valsB1, valsB2 });

                XrecordInfo xi = new XrecordInfo(DIC_NAME);

                xi.AddDict(dictionary); 
                trx.Commit();
            }
        }

        [CommandMethod("XrecordDictionaryGet")]
        public void XrecordDictionaryGet()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            using (Transaction trx = db.TransactionManager.StartTransaction())
            {
                XrecordInfo xi = new XrecordInfo(DIC_NAME);           
                Dictionary<string, List<string[]>> dictionary = xi.GetDict();

                foreach (KeyValuePair<string, List<string[]>> kvp in dictionary)
                {
                    ed.WriteMessage("\n{0}", kvp.Key);
                    int i = 1;
                    foreach (string[] strings in kvp.Value)
                    {

                        ed.WriteMessage("\n{0,15:D} {1}","Array", i);
                        foreach (string str in strings)
                        {
                            ed.WriteMessage("\n{0,15:D}", str);
                        }
                        i++;
                    }

                }

                trx.Commit();
            }
        }

Not very good but for example Helper Class
Code: [Select]

    public class XrecordInfo
     {
     
         private Database _db;
         private Transaction _trx;
         Database db { get { return _db; } }
         Transaction trx { get { return _trx; } }
         string DictionaryName { get; set; }


         public XrecordInfo()
         {
             _db = HostApplicationServices.WorkingDatabase;
             _trx = _db.TransactionManager.TopTransaction;
         
         }


         public XrecordInfo(string dictName)
             : this()
         {
             DictionaryName = dictName;
         }

 
         public void AddDict(Dictionary<string, List<string[]>> dict)
         {

             DBDictionary nod = (DBDictionary)trx.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
             DBDictionary dic = new DBDictionary();
             nod.SetAt(DictionaryName, dic);
             trx.AddNewlyCreatedDBObject(dic, true);

             foreach(KeyValuePair<string, List<string[]>> kvp in dict)
             {                                                 
                 DBDictionary nestedDic = new DBDictionary();
                 dic.SetAt(kvp.Key, nestedDic);
                 trx.AddNewlyCreatedDBObject(nestedDic, true);
                 int i = 1;
                 foreach (string[] vals in kvp.Value)
                 {
                     Xrecord xr = new Xrecord();
                     TypedValueList tvl = new TypedValueList();
                     
                     foreach (string val in vals)
                     {
                         tvl.Add(1, val);
                     }
                     xr.Data = tvl;
                     nestedDic.SetAt(String.Format("array{0}", i), xr);
                     trx.AddNewlyCreatedDBObject(xr, true);
                     i++;
                 }
                 
             
             }


         }

         public Dictionary<string, List<string[]>> GetDict()
         {                                                                                             
             Dictionary<string, List<string[]>> dictionary = new Dictionary<string, List<string[]>>();

             DBDictionary nod = (DBDictionary)trx.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
             DBDictionary dic = (DBDictionary)trx.GetObject(nod.GetAt(DictionaryName), OpenMode.ForRead);

             foreach (DBDictionaryEntry entry in dic)
             {
                 DBDictionary nestedDic = (DBDictionary)trx.GetObject(dic.GetAt(entry.Key), OpenMode.ForRead);
                 List<string[]> vals = new List<string[]>();
                 foreach (DBDictionaryEntry nestedEntry in nestedDic)
                 {

                     Xrecord xr = (Xrecord)trx.GetObject(nestedDic.GetAt(nestedEntry.Key), OpenMode.ForRead);

                     TypedValueList tvl = xr.Data;
                     string[] strings = new string[tvl.Count];
                     for (int i = 0; i < tvl.Count; i++)
                     {
                         strings[i] = tvl[i].Value.ToString();
                     }
                     vals.Add(strings);
                 }

                 dictionary.Add(entry.Key, vals); 
                                     
                                 
             }


             return dictionary;

         }

     }




Uses Tony T's TypedValueList
Code: [Select]
public class TypedValueList : List<TypedValue>
    {
        // With thanks to Tony Tanzillo
        // http://www.theswamp.org/index.php?topic=14495.msg186823#msg186823
        //
        public TypedValueList(params TypedValue[] args)
        {
            AddRange(args);
        }

        // Make it a bit easier to add items:

        public void Add(int typecode, object value)
        {
            base.Add(new TypedValue(typecode, value));
        }
        public void Add(LispDataType type, object value)
        {
            Add(new TypedValue((int)type, value));
        }
        public void Add(DxfCode code, object value)
        {
            Add(new TypedValue((int)code, value));
        }

        // Implicit conversion to SelectionFilter
        public static implicit operator SelectionFilter(TypedValueList src)
        {
            return src != null ? new SelectionFilter(src) : null;
        }

        // Implicit conversion to ResultBuffer
        public static implicit operator ResultBuffer(TypedValueList src)
        {
            return src != null ? new ResultBuffer(src) : null;
        }

        // Implicit conversion to TypedValue[]
        public static implicit operator TypedValue[](TypedValueList src)
        {
            return src != null ? src.ToArray() : null;
        }

        // Implicit conversion from TypedValue[]
        public static implicit operator TypedValueList(TypedValue[] src)
        {
            return src != null ? new TypedValueList(src) : null;
        }

        // Implicit conversion from SelectionFilter
        public static implicit operator TypedValueList(SelectionFilter src)
        {
            return src != null ? new TypedValueList(src.GetFilter()) : null;
        }

        // Implicit conversion from ResultBuffer
        public static implicit operator TypedValueList(ResultBuffer src)
        {
            return src != null ? new TypedValueList(src.AsArray()) : null;
        }
    }