プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

ZenでC++ライクなTupleを作る

 はい、なんかブログを書けという圧が強い気がしたので、何か書きます。

 というわけで、いつでもどこでもメタい事を考えていると、どうしても欲しくなりますよね、Zen言語でコンパイル時動的型。 ですが、Zenといえど流石に構造体を自在に作ることは出来ません。(出来ないよね?出来たら凄いね。)

 

 しかし、C++のtupleのような使い方をする構造体なら作ることが可能です。

 これで型の配列さえ作れば、後は構造体に出来るので、若干フィールドへのアクセスが面倒くさい点を除けば、何でも出来ますね!

const std = @import("std");

pub fn main() anyerror! void {
  const Name = [:0]const u8;
  const Age = u32;
  const Height = u32;

  const t = tuple( &[_]type {Name, Age, Height} )
            .init(.{ "nodamushi", 19, 182 });

  std.debug.warn("name={}, age={}, height={}\n",
                 .{ t.get(0),  t.get(1),  t.get(2) });
}


/// C++のtupleのような型を生成します
pub fn tuple(comptime types: []const type) type{
  return _tuple(types, 0);
}

fn _tuple(comptime types: []const type, comptime index:usize) type{
  if(types.len == index){
    return void;
  } else {
    const Car = types[index];
    const Cdr = _tuple(types, index+1);

    return struct {
      const Self = @This();

      pub const len = types.len - index;
      car: Car,
      cdr: Cdr,

      pub inline fn init(value: var) Self {
        return Self{
          .car = value[index],
          .cdr = if(void == Cdr) {} else Cdr.init(value),
        };
      }

      pub inline fn get(self: Self, comptime idx:usize) types[idx] {
        if(index == idx) {
          return self.car;
        } else {
          return self.cdr.get(idx);
        }
      }

      pub inline fn ptr(self: *Self, comptime idx:usize) *types[idx] {
        if(index == idx){
          return &self.car;
        } else {
          return self.cdr.ptr(idx);
        }
      }
    };
  }
}