4

我编写了一个变体类,它将用作动态语言中的主要类型,最终将允许 256 种不同类型的值(标头是无符号字节,实际只使用了 20 种)。我现在想实现类型之间的转换/转换。

我最初的想法是一个查找表,但所需的内存量使其实现起来不切实际。

有哪些替代方案?现在,我正在考虑其他三种研究方法和其他人的建议:

  1. 将类型分组为更大的子集,例如数字或集合或其他。
  2. 创建一个具有 CanCast(from, to) 和 Cast(Variant) 方法的转换接口,并允许将实现该接口的类添加到列表中,然后可以检查该列表是否有任何转换类可以进行转换。
  3. 与 (1) 类似,但要制作几个主类型,并且铸造是从原始类型到主类型然后再到最终类型的两步过程。

什么是最好的系统?

编辑:我已经添加了赏金,因为我仍然不确定最好的系统,当前的答案非常好,并且肯定得到了我的 +1,但肯定有人这样做并且可以说出最好的方法是什么。

4

3 回答 3

1

做过类似的事情。

您可以在“标题”中添加另一个字节,指示其实际存储的类型。

C 风格编程语言的示例:

typedef
enum VariantInternalType {
  vtUnassigned = 0;
  vtByte = 1;
  vtCharPtr = 2; // <-- "plain c" string
  vtBool = 3;
  // other supported data types
}

// --> real data
typedef
struct VariantHeader {
  void* Reserved; // <-- your data (byte or void*)
  VariantInternalType VariantInternalType;  
}

// --> hides real data
typedef
  byte[sizeof(VariantHeader)] Variant;

// allocates & assign a byte data type to a variant
Variant ByteToVar(byte value)
{
  VariantHeader MyVariantHeader;
  Variant MyVariant;

  MyVariantHeader.VariantInternalType = VariantInternalType.vtByte;
  MyVariantHeader.Reserved = value;  

  memcpy (&MyVariant, &MyVariantHeader, sizeof(Variant));

  return myVariant;
}

// allocates & assign a char array data type to a variant
Variant CharPtrToVar(char* value)
{
  VariantHeader MyVariantHeader;
  Variant MyVariant;

  MyVariantHeader.VariantInternalType = VariantInternalType.vtByte;
  MyVariantHeader.Reserved = strcpy(value);  

  // copy exposed struct type data to hidden array data
  memcpy(&MyVariant, &MyVariantHeader, sizeof(Variant));

  return myVariant;
}

// deallocs memory for any internal data type
void freeVar(Variant &myVariant)
{
  VariantHeader MyVariantHeader;

  // copy exposed struct type data to hidden array data
  memcpy(&MyVariantHeader, &MyVariant, sizeof(VariantHeader));

  switch (MyVariantHeader.VariantInternalType) {
    case vtCharPtr:
      strfree(MyVariantHeader.reserved);
    break;

    // other types

    default:
    break;
  }

  // copy exposed struct type data to hidden array data
  memcpy(&MyVariant, &MyVariantHeader, sizeof(Variant));
}

bool isVariantType(Variant &thisVariant, VariantInternalType thisType)
{
  VariantHeader MyVariantHeader;

  // copy exposed struct type data to hidden array data
  memcpy(&MyVariantHeader, &MyVariant, sizeof(VariantHeader));

  return (MyVariant.VariantInternalType == thisType);
}

// -------

void main()
{
  Variant myVariantStr = CharPtrToVar("Hello World");
  Variant myVariantByte = ByteToVar(42);

  char* myString = null;
  byte  myByte = 0;

  if isVariantType(myVariantStr, vtCharPtr) {
    myString = VarToCharPtr(myVariantStr);
    // print variant string into screen
  }

  // ...    
}

这只是一个建议,未经测试。

于 2011-05-06T20:14:02.790 回答
1

我的系统非常“重”(大量代码),但速度非常快,并且功能非常丰富(跨平台 C++)。我不确定你想在设计上走多远,但这是我所做的最重要的部分:

DatumState- 持有“类型”的“枚举”的类,加上本机值,这是所有原始类型之间的“联合”,包括void*. 此类与所有类型解耦,可用于任何本机/原始类型和“引用”void*类型。由于 " enum" 也有 " VALUE_OF" 和 " REF_TO" 上下文,因此此类可以呈现为“完全包含” a float(或某些原始类型),或“引用但不拥有” a float(或某些原始类型)。(我实际上有“ VALUE_OF”、“ REF_TO”和“ PTR_TO”上下文,所以我可以在逻辑上存储一个,一个不能为空的引用

Datum- 完全包含 a 的类DatumState,但它扩展了其接口以适应各种“知名”类型(如MyDateMyColorMyFileName等)。这些知名类型实际上存储在成员void*内部DatumState。但是,由于“ enum”部分DatumState具有“ VALUE_OF”和“ REF_TO”上下文,它可以表示“ pointer-to-MyDate”或“ value-of-MyDate”。

DatumStateHandle- 使用(众所周知的)类型(如MyDate, MyColor,MyFileName等)参数化的帮助模板类。这是用于Datum从众所周知的类型中提取状态的访问器。默认实现适用于大多数类,但任何具有特定访问语义的类只会覆盖其特定模板参数化/实现,用于该模板类中的一个或多个成员函数。

Macros, helper functions, and some other supporting stuffDatum- 为了简化在我的/中“添加”众所周知的类型Variant,我发现将逻辑集中到几个宏中很方便,提供一些支持功能,如运算符重载,并在我的代码中建立一些其他约定。

作为这个实现的“副作用”,我得到了很多好处,包括引用和值语义、所有类型的“null”选项以及对所有类型的异构容器的支持。

例如,您可以创建一组整数并为其编制索引:

int my_ints[10];
Datum d(my_ints, 10/*count*/);
for(long i = 0; i < d.count(); ++i)
{
  d[i] = i;
}

类似地,某些数据类型由字符串或枚举索引:

MyDate my_date = MyDate::GetDateToday();
Datum d(my_date);
cout << d["DAY_OF_WEEK"] << endl;
cout << d[MyDate::DAY_OF_WEEK] << endl; // alternative

我可以存储项目集(本机)或集Datum(包装每个项目)。对于任何一种情况,我都可以递归地“解包”:

MyDate my_dates[10];
Datum d(my_dates, 10/*count*/);
for(long i = 0; i < d.count(); ++i)
{
  cout << d[i][MyDate::DAY_OF_WEEK] << endl;
}

有人可能会争辩说我的 " REF_TO" 和 " VALUE_OF" 语义是矫枉过正的,但它们对于 "set-unwrapping" 是必不可少的。

我已经Variant用九种不同的设计完成了这个“”的事情,我目前是“最重的”(大多数代码),但我最喜欢的一个(几乎是最快的,对象占用空间很小),我已经弃用了其他八种设计供我使用。

我的设计的“缺点”是:

  1. 对象是通过 static_cast<>()a访问的void* (类型安全且相当快,但需要间接;但是,副作用是设计支持“ null”的存储。)
  2. Datum由于通过接口公开了众所周知的类型,因此编译时间更长(但DatumState如果您不想要众所周知的类型 API,您可以使用)。

无论您的设计如何,我都会推荐以下内容:

  1. 使用“ enum”或其他东西来告诉您“类型”,与“”分开。(我知道您可以将它们压缩成一个“ int”或带有位包装的东西,但是随着新类型的引入,访问速度很慢并且维护起来非常棘手。)

  2. 依靠模板或其他东西来集中操作,使用特定类型(覆盖)处理的机制(假设您要处理非平凡类型)。

游戏的名称是“添加新类型时的简化维护”(或者至少对我来说是这样)。就像一篇好的学期论文一样,如果你重写、重写、重写,以保持或增加你的功能,因为你不断删除维护系统所需的代码(例如,最大限度地减少适应新类型所需的工作量)到您现有的Variant基础设施)。

祝你好运!

于 2011-05-13T04:49:57.990 回答
0

也许您已经完成了计算,但是查找表所需的内存量并没有那么多。

如果您只需要检查类型是否兼容,那么您需要 (256*256)/2 位。这需要 4k 的内存。

如果还需要指向转换函数的指针,则需要 (256*256)/2 指针。这需要 32 位机器上的 128k 内存和 64 位机器上的 256k 内存。如果您愿意做一些低级地址布局,您可以在 32 位和 64 位机器上将其降低到 64k。

于 2011-05-26T21:10:55.063 回答