github.com/astrogo/cfitsio@v0.1.0/table.go (about) 1 package cfitsio 2 3 // #include "go-cfitsio.h" 4 // #include "go-cfitsio-utils.h" 5 import "C" 6 import ( 7 "fmt" 8 "reflect" 9 "strconv" 10 "strings" 11 "unsafe" 12 ) 13 14 type TypeCode int 15 16 const ( 17 TBIT TypeCode = C.TBIT /* codes for FITS table data types */ 18 TBYTE TypeCode = C.TBYTE 19 TSBYTE TypeCode = C.TSBYTE 20 TLOGICAL TypeCode = C.TLOGICAL 21 TSTRING TypeCode = C.TSTRING 22 TUSHORT TypeCode = C.TUSHORT 23 TSHORT TypeCode = C.TSHORT 24 TUINT TypeCode = C.TUINT 25 TINT TypeCode = C.TINT 26 TULONG TypeCode = C.TULONG 27 TLONG TypeCode = C.TLONG 28 TINT32BIT TypeCode = C.TINT32BIT /* used when returning datatype of a column */ 29 TFLOAT TypeCode = C.TFLOAT 30 TLONGLONG TypeCode = C.TLONGLONG 31 TDOUBLE TypeCode = C.TDOUBLE 32 TCOMPLEX TypeCode = C.TCOMPLEX 33 TDBLCOMPLEX TypeCode = C.TDBLCOMPLEX 34 35 // variable length arrays 36 TVLABIT TypeCode = -C.TBIT /* codes for FITS table data types */ 37 TVLABYTE TypeCode = -C.TBYTE 38 TVLASBYTE TypeCode = -C.TSBYTE 39 TVLALOGICAL TypeCode = -C.TLOGICAL 40 TVLASTRING TypeCode = -C.TSTRING 41 TVLAUSHORT TypeCode = -C.TUSHORT 42 TVLASHORT TypeCode = -C.TSHORT 43 TVLAUINT TypeCode = -C.TUINT 44 TVLAINT TypeCode = -C.TINT 45 TVLAULONG TypeCode = -C.TULONG 46 TVLALONG TypeCode = -C.TLONG 47 TVLAINT32BIT TypeCode = -C.TINT32BIT /* used when returning datatype of a column */ 48 TVLAFLOAT TypeCode = -C.TFLOAT 49 TVLALONGLONG TypeCode = -C.TLONGLONG 50 TVLADOUBLE TypeCode = -C.TDOUBLE 51 TVLACOMPLEX TypeCode = -C.TCOMPLEX 52 TVLADBLCOMPLEX TypeCode = -C.TDBLCOMPLEX 53 ) 54 55 func (tc TypeCode) String() string { 56 switch tc { 57 case TBIT: 58 return "TBIT" 59 case TBYTE: 60 return "TBYTE" 61 case TSBYTE: 62 return "TSBYTE" 63 case TLOGICAL: 64 return "TLOGICAL" 65 case TSTRING: 66 return "TSTRING" 67 case TUSHORT: 68 return "TUSHORT" 69 case TSHORT: 70 return "TSHORT" 71 case TUINT: 72 return "TUINT" 73 case TINT: 74 return "TINT" 75 case TULONG: 76 return "TULONG" 77 case TLONG: 78 return "TLONG" 79 case TFLOAT: 80 return "TFLOAT" 81 case TLONGLONG: 82 return "TLONGLONG" 83 case TDOUBLE: 84 return "TDOUBLE" 85 case TCOMPLEX: 86 return "TCOMPLEX" 87 case TDBLCOMPLEX: 88 return "TDBLCOMPLEX" 89 90 case TVLABIT: 91 return "TVLABIT" 92 case TVLABYTE: 93 return "TVLABYTE" 94 case TVLASBYTE: 95 return "TVLASBYTE" 96 case TVLALOGICAL: 97 return "TVLALOGICAL" 98 case TVLASTRING: 99 return "TVLASTRING" 100 case TVLAUSHORT: 101 return "TVLAUSHORT" 102 case TVLASHORT: 103 return "TVLASHORT" 104 case TVLAUINT: 105 return "TVLAUINT" 106 case TVLAINT: 107 return "TVLAINT" 108 case TVLAULONG: 109 return "TVLAULONG" 110 case TVLALONG: 111 return "TVLALONG" 112 case TVLAFLOAT: 113 return "TVLAFLOAT" 114 case TVLALONGLONG: 115 return "TVLALONGLONG" 116 case TVLADOUBLE: 117 return "TVLADOUBLE" 118 case TVLACOMPLEX: 119 return "TVLACOMPLEX" 120 case TVLADBLCOMPLEX: 121 return "TVLADBLCOMPLEX" 122 } 123 panic("unreachable") 124 } 125 126 var g_cfits2go map[TypeCode]reflect.Type 127 var g_go2cfits map[reflect.Type]TypeCode 128 129 func govalue_from_repeat(rt reflect.Type, n int) Value { 130 var v Value 131 switch n { 132 case 1: 133 rv := reflect.New(rt) 134 v = rv.Elem().Interface() 135 default: 136 // FIXME: distinguish b/w reflect.Slice and reflect.Array 137 // FIXME: use reflect.MakeArray + reflect.ArrayOf when available 138 rv := reflect.MakeSlice(reflect.SliceOf(rt), n, n) 139 v = rv.Interface() 140 } 141 return v 142 } 143 144 func govalue_from_typecode(t TypeCode, n int) Value { 145 var v Value 146 rt, ok := g_cfits2go[t] 147 if !ok { 148 panic(fmt.Errorf("cfitsio: invalid TypeCode value [%v]", int(t))) 149 150 } 151 // FIXME: distinguish b/w reflect.Slice and reflect.Array 152 v = govalue_from_repeat(rt, n) 153 return v 154 } 155 156 type Table struct { 157 f *File 158 id C.int 159 header Header 160 nrows int64 161 cols []Column 162 col2idx map[string]int // associates a column name to its index 163 data interface{} 164 } 165 166 func (hdu *Table) Close() error { 167 hdu.f = nil 168 return nil 169 } 170 171 func (hdu *Table) Header() Header { 172 return hdu.header 173 } 174 175 func (hdu *Table) Type() HDUType { 176 return hdu.header.htype 177 } 178 179 func (hdu *Table) Name() string { 180 card := hdu.header.Get("EXTNAME") 181 if card == nil { 182 return "" 183 } 184 return card.Value.(string) 185 } 186 187 func (hdu *Table) Version() int { 188 card := hdu.header.Get("EXTVER") 189 if card == nil { 190 return 1 191 } 192 return card.Value.(int) 193 } 194 195 func (hdu *Table) Data(interface{}) error { 196 var err error 197 if hdu.data == nil { 198 err = hdu.load() 199 } 200 return err 201 } 202 203 func (hdu *Table) load() error { 204 return nil 205 } 206 207 func (hdu *Table) NumRows() int64 { 208 return hdu.nrows 209 } 210 211 func (hdu *Table) NumCols() int { 212 return len(hdu.cols) 213 } 214 215 func (hdu *Table) Cols() []Column { 216 return hdu.cols 217 } 218 219 func (hdu *Table) Col(i int) *Column { 220 return &hdu.cols[i] 221 } 222 223 // Index returns the index of the first column with name `n` or -1 224 func (hdu *Table) Index(n string) int { 225 idx, ok := hdu.col2idx[n] 226 if !ok { 227 return -1 228 } 229 return idx 230 } 231 232 func (hdu *Table) readRow(irow int64) error { 233 err := hdu.seekHDU() 234 if err != nil { 235 return err 236 } 237 for icol := range hdu.cols { 238 col := &hdu.cols[icol] 239 err = col.read(hdu.f, icol, irow, &col.Value) 240 if err != nil { 241 return err 242 } 243 } 244 return err 245 } 246 247 // ReadRange reads rows over the range [beg, end) and returns the corresponding iterator. 248 // if end > maxrows, the iteration will stop at maxrows 249 // ReadRange has the same semantics than a `for i=0; i < max; i+=inc {...}` loop 250 func (hdu *Table) ReadRange(beg, end, inc int64) (*Rows, error) { 251 var rows *Rows 252 err := hdu.seekHDU() 253 if err != nil { 254 return rows, err 255 } 256 257 maxrows := hdu.NumRows() 258 if end > maxrows { 259 end = maxrows 260 } 261 262 if beg < 0 { 263 beg = 0 264 } 265 266 cols := make([]int, len(hdu.cols)) 267 for i := range hdu.cols { 268 cols[i] = i 269 } 270 271 rows = &Rows{ 272 table: hdu, 273 cols: cols, 274 i: beg, 275 n: end, 276 inc: inc, 277 cur: beg - inc, 278 err: nil, 279 icols: make(map[reflect.Type][][2]int), 280 } 281 return rows, err 282 } 283 284 // Read reads rows over the range [beg, end) and returns the corresponding iterator. 285 // if end > maxrows, the iteration will stop at maxrows 286 // ReadRange has the same semantics than a `for i=0; i < max; i++ {...}` loop 287 func (hdu *Table) Read(beg, end int64) (*Rows, error) { 288 return hdu.ReadRange(beg, end, 1) 289 } 290 291 func (hdu *Table) seekHDU() error { 292 c_status := C.int(0) 293 c_htype := C.int(0) 294 C.fits_movabs_hdu(hdu.f.c, hdu.id, &c_htype, &c_status) 295 if c_status > 0 { 296 return to_err(c_status) 297 } 298 return nil 299 } 300 301 func newTable(f *File, hdr Header, i int) (hdu HDU, err error) { 302 c_status := C.int(0) 303 c_id := C.int(0) 304 C.fits_get_hdu_num(f.c, &c_id) 305 if c_status > 0 { 306 return nil, to_err(c_status) 307 } 308 309 c_nrows := C.long(0) 310 C.fits_get_num_rows(f.c, &c_nrows, &c_status) 311 if c_status > 0 { 312 return nil, to_err(c_status) 313 } 314 315 c_ncols := C.int(0) 316 C.fits_get_num_cols(f.c, &c_ncols, &c_status) 317 if c_status > 0 { 318 return nil, to_err(c_status) 319 } 320 321 ncols := int(c_ncols) 322 cols := make([]Column, ncols) 323 col2idx := make(map[string]int, ncols) 324 325 get := func(str string, ii int) *Card { 326 return hdr.Get(fmt.Sprintf(str+"%d", ii+1)) 327 } 328 for ii := 0; ii < ncols; ii++ { 329 col := &cols[ii] 330 // column name 331 { 332 c_status := C.int(0) 333 c_tmpl := C.CString(fmt.Sprintf("%d", ii+1)) 334 defer C.free(unsafe.Pointer(c_tmpl)) 335 c_name := C.CStringN(C.FLEN_CARD) 336 defer C.free(unsafe.Pointer(c_name)) 337 c_colnum := C.int(0) 338 C.fits_get_colname(f.c, C.CASESEN, c_tmpl, c_name, &c_colnum, &c_status) 339 if c_status > 0 { 340 return nil, to_err(c_status) 341 } 342 col.Name = C.GoString(c_name) 343 col2idx[col.Name] = ii 344 } 345 346 card := get("TFORM", ii) 347 if card != nil { 348 col.Format = card.Value.(string) 349 } 350 351 card = get("TUNIT", ii) 352 if card != nil { 353 col.Unit = card.Value.(string) 354 } 355 356 card = get("TNULL", ii) 357 if card != nil { 358 col.Null = card.Value.(string) 359 } 360 361 card = get("TSCAL", ii) 362 if card != nil { 363 switch vv := card.Value.(type) { 364 case float64: 365 col.Bscale = vv 366 case int64: 367 col.Bscale = float64(vv) 368 default: 369 panic(fmt.Errorf("unhandled type [%T]", vv)) 370 } 371 //col.Bscale = card.Value.(float64) 372 } else { 373 col.Bscale = 1.0 374 } 375 376 card = get("TZERO", ii) 377 if card != nil { 378 switch vv := card.Value.(type) { 379 case float64: 380 col.Bzero = vv 381 case int64: 382 col.Bzero = float64(vv) 383 default: 384 panic(fmt.Errorf("unhandled type [%T]", vv)) 385 } 386 //col.Bzero = card.Value.(float64) 387 } else { 388 col.Bzero = 0.0 389 } 390 391 card = get("TDISP", ii) 392 if card != nil { 393 col.Display = card.Value.(string) 394 } 395 396 { 397 // int fits_read_tdimll / ffgtdmll 398 //(fitsfile *fptr, int colnum, int maxdim, > int *naxis, 399 //LONGLONG *naxes, int *status) 400 401 } 402 card = get("TDIM", ii) 403 if card != nil { 404 dims := card.Value.(string) 405 dims = strings.Replace(dims, "(", "", -1) 406 dims = strings.Replace(dims, ")", "", -1) 407 toks := make([]string, 0) 408 for _, tok := range strings.Split(dims, ",") { 409 tok = strings.Trim(tok, " \t\n") 410 if tok == "" { 411 continue 412 } 413 toks = append(toks, tok) 414 } 415 col.Dim = make([]int64, 0, len(toks)) 416 for _, tok := range toks { 417 dim, err := strconv.ParseInt(tok, 10, 64) 418 if err != nil { 419 return nil, err 420 } 421 col.Dim = append(col.Dim, dim) 422 } 423 } 424 425 card = get("TBCOL", ii) 426 if card != nil { 427 col.Start = card.Value.(int64) 428 } 429 430 { 431 c_type := C.int(0) 432 c_repeat := C.long(0) 433 c_width := C.long(0) 434 c_status := C.int(0) 435 c_col := C.int(ii + 1) // 1-based index 436 C.fits_get_coltype(f.c, c_col, &c_type, &c_repeat, &c_width, &c_status) 437 if c_status > 0 { 438 return nil, to_err(c_status) 439 } 440 col.Type = TypeCode(c_type) 441 col.Len = int(c_repeat) 442 col.Value = govalue_from_typecode(col.Type, col.Len) 443 } 444 } 445 446 hdu = &Table{ 447 f: f, 448 id: c_id, 449 header: hdr, 450 nrows: int64(c_nrows), 451 cols: cols, 452 col2idx: col2idx, 453 data: nil, 454 } 455 return hdu, err 456 } 457 458 // NewTable creates a new table in the given FITS file 459 func NewTable(f *File, name string, cols []Column, hdutype HDUType) (*Table, error) { 460 var err error 461 var table *Table 462 mode, err := f.Mode() 463 if err != nil { 464 return table, err 465 } 466 if mode == ReadOnly { 467 return table, READONLY_FILE 468 } 469 470 nhdus := len(f.hdus) 471 472 if len(cols) <= 0 { 473 return table, fmt.Errorf("cfitsio.NewTable: invalid number of columns (%v)", len(cols)) 474 } 475 476 c_status := C.int(0) 477 c_sz := C.int(len(cols)) 478 c_types := C.char_array_new(c_sz) 479 defer C.free(unsafe.Pointer(c_types)) 480 c_forms := C.char_array_new(c_sz) 481 defer C.free(unsafe.Pointer(c_forms)) 482 c_units := C.char_array_new(c_sz) 483 defer C.free(unsafe.Pointer(c_units)) 484 c_hduname := C.CString(name) 485 defer C.free(unsafe.Pointer(c_hduname)) 486 487 for i := 0; i < len(cols); i++ { 488 c_idx := C.int(i) 489 col := &cols[i] 490 c_name := C.CString(col.Name) 491 defer C.free(unsafe.Pointer(c_name)) 492 C.char_array_set(c_types, c_idx, c_name) 493 494 err = col.inferFormat(hdutype) 495 if err != nil { 496 return table, err 497 } 498 c_form := C.CString(col.Format) 499 defer C.free(unsafe.Pointer(c_form)) 500 C.char_array_set(c_forms, c_idx, c_form) 501 502 c_unit := C.CString(col.Unit) 503 defer C.free(unsafe.Pointer(c_unit)) 504 C.char_array_set(c_units, c_idx, c_unit) 505 } 506 507 C.fits_create_tbl(f.c, C.int(hdutype), 0, C.int(len(cols)), c_types, c_forms, c_units, c_hduname, &c_status) 508 if c_status > 0 { 509 return table, to_err(c_status) 510 } 511 512 hdu, err := f.readHDU(nhdus) 513 if err != nil { 514 return table, err 515 } 516 f.hdus = append(f.hdus, hdu) 517 table = hdu.(*Table) 518 519 return table, err 520 } 521 522 // NewTableFrom creates a new table in the given FITS file, using the struct v as schema 523 func NewTableFrom(f *File, name string, v Value, hdutype HDUType) (*Table, error) { 524 rv := reflect.Indirect(reflect.ValueOf(v)) 525 rt := rv.Type() 526 if rt.Kind() != reflect.Struct { 527 return nil, fmt.Errorf("cfitsio: NewTableFrom takes a struct value. got: %T", v) 528 } 529 cols := make([]Column, rt.NumField()) 530 for i := range cols { 531 ft := rt.Field(i) 532 name := ft.Tag.Get("fits") 533 if name == "" { 534 name = ft.Name 535 } 536 n := 0 537 if ft.Type.Kind() == reflect.Array { 538 n = ft.Type.Len() 539 } 540 cols[i] = Column{ 541 Name: name, 542 Len: n, 543 Value: rv.Field(i).Interface(), 544 } 545 } 546 return NewTable(f, name, cols, hdutype) 547 } 548 549 // Write writes a row to the table 550 func (hdu *Table) Write(args ...interface{}) error { 551 552 err := hdu.seekHDU() 553 if err != nil { 554 return err 555 } 556 557 irow := hdu.NumRows() 558 559 defer func() { 560 // update nrows 561 c_nrows := C.long(0) 562 c_status := C.int(0) 563 C.fits_get_num_rows(hdu.f.c, &c_nrows, &c_status) 564 if c_status > 0 { 565 return 566 } 567 hdu.nrows = int64(c_nrows) 568 }() 569 570 switch len(args) { 571 case 0: 572 return fmt.Errorf("cfitsio: Table.Write needs at least one argument") 573 case 1: 574 // maybe special case: map? struct? 575 rt := reflect.TypeOf(args[0]).Elem() 576 switch rt.Kind() { 577 case reflect.Map: 578 return hdu.writeMap(irow, *args[0].(*map[string]interface{})) 579 case reflect.Struct: 580 return hdu.writeStruct(irow, args[0]) 581 } 582 } 583 584 return hdu.write(irow, args...) 585 } 586 587 func (hdu *Table) writeMap(irow int64, data map[string]interface{}) error { 588 var err error 589 590 for k, v := range data { 591 icol := hdu.Index(k) 592 if icol < 0 { 593 continue 594 } 595 col := &hdu.cols[icol] 596 col.Value = v 597 err = col.write(hdu.f, icol, irow, col.Value) 598 if err != nil { 599 return err 600 } 601 } 602 603 return err 604 } 605 606 func (hdu *Table) writeStruct(irow int64, data interface{}) error { 607 var err error 608 rt := reflect.TypeOf(data).Elem() 609 rv := reflect.ValueOf(data).Elem() 610 icols := make([][2]int, 0, rt.NumField()) 611 for i := 0; i < rt.NumField(); i++ { 612 f := rt.Field(i) 613 n := f.Tag.Get("fits") 614 if n == "" { 615 n = f.Name 616 } 617 icol := hdu.Index(n) 618 if icol >= 0 { 619 icols = append(icols, [2]int{i, icol}) 620 } 621 } 622 623 for _, icol := range icols { 624 vv := rv.Field(icol[0]) 625 col := &hdu.cols[icol[1]] 626 col.Value = vv.Interface() 627 err = col.write(hdu.f, icol[1], irow, col.Value) 628 if err != nil { 629 return err 630 } 631 } 632 return err 633 } 634 635 func (hdu *Table) write(irow int64, args ...interface{}) error { 636 var err error 637 638 nargs := len(args) 639 if nargs > len(hdu.cols) { 640 nargs = len(hdu.cols) 641 } 642 643 for i := 0; i < nargs; i++ { 644 col := &hdu.cols[i] 645 rv := reflect.ValueOf(args[i]).Elem() 646 vv := reflect.ValueOf(&col.Value).Elem() 647 vv.Set(rv) 648 err = col.write(hdu.f, i, irow, col.Value) 649 if err != nil { 650 return err 651 } 652 } 653 return err 654 } 655 656 // CopyTable copies all the rows from src into dst. 657 func CopyTable(dst, src *Table) error { 658 return CopyTableRange(dst, src, 0, src.NumRows()) 659 } 660 661 // CopyTableRange copies the rows interval [beg,end) from src into dst 662 func CopyTableRange(dst, src *Table, beg, end int64) error { 663 var err error 664 if dst == nil { 665 return fmt.Errorf("cfitsio: dst pointer is nil") 666 } 667 if src == nil { 668 return fmt.Errorf("cfitsio: src pointer is nil") 669 } 670 671 defer func() { 672 // update nrows 673 c_nrows := C.long(0) 674 c_status := C.int(0) 675 C.fits_get_num_rows(dst.f.c, &c_nrows, &c_status) 676 if c_status > 0 { 677 return 678 } 679 dst.nrows = int64(c_nrows) 680 }() 681 682 err = dst.seekHDU() 683 if err != nil { 684 return err 685 } 686 err = src.seekHDU() 687 if err != nil { 688 return err 689 } 690 691 hdr := src.Header() 692 buf := make([]byte, int(hdr.Axes()[0])) 693 slice := (*reflect.SliceHeader)((unsafe.Pointer(&buf))) 694 c_ptr := (*C.uchar)(unsafe.Pointer(slice.Data)) 695 c_len := C.LONGLONG(len(buf)) 696 c_orow := C.LONGLONG(dst.nrows) 697 for irow := beg; irow < end; irow++ { 698 c_status := C.int(0) 699 c_row := C.LONGLONG(irow) + 1 // from 0-based to 1-based index 700 C.fits_read_tblbytes(src.f.c, c_row, 1, c_len, c_ptr, &c_status) 701 if c_status > 0 { 702 return to_err(c_status) 703 } 704 705 C.fits_write_tblbytes(dst.f.c, c_orow+c_row, 1, c_len, c_ptr, &c_status) 706 if c_status > 0 { 707 return to_err(c_status) 708 } 709 } 710 711 return err 712 } 713 714 func init() { 715 g_hdus[ASCII_TBL] = newTable 716 g_hdus[BINARY_TBL] = newTable 717 g_cfits2go = map[TypeCode]reflect.Type{ 718 TBIT: reflect.TypeOf((*byte)(nil)).Elem(), 719 TBYTE: reflect.TypeOf((*byte)(nil)).Elem(), 720 TSBYTE: reflect.TypeOf((*int8)(nil)).Elem(), 721 TLOGICAL: reflect.TypeOf((*bool)(nil)).Elem(), 722 TSTRING: reflect.TypeOf((*string)(nil)).Elem(), 723 TUSHORT: reflect.TypeOf((*uint16)(nil)).Elem(), 724 TSHORT: reflect.TypeOf((*int16)(nil)).Elem(), 725 TUINT: reflect.TypeOf((*uint32)(nil)).Elem(), 726 TINT: reflect.TypeOf((*int32)(nil)).Elem(), 727 TULONG: reflect.TypeOf((*uint64)(nil)).Elem(), 728 TLONG: reflect.TypeOf((*int64)(nil)).Elem(), 729 TFLOAT: reflect.TypeOf((*float32)(nil)).Elem(), 730 TLONGLONG: reflect.TypeOf((*int64)(nil)).Elem(), 731 TDOUBLE: reflect.TypeOf((*float64)(nil)).Elem(), 732 TCOMPLEX: reflect.TypeOf((*complex64)(nil)).Elem(), 733 TDBLCOMPLEX: reflect.TypeOf((*complex128)(nil)).Elem(), 734 735 TVLABIT: reflect.TypeOf((*[]byte)(nil)).Elem(), 736 TVLABYTE: reflect.TypeOf((*[]byte)(nil)).Elem(), 737 TVLASBYTE: reflect.TypeOf((*[]int8)(nil)).Elem(), 738 TVLALOGICAL: reflect.TypeOf((*[]bool)(nil)).Elem(), 739 TVLASTRING: reflect.TypeOf((*[]string)(nil)).Elem(), 740 TVLAUSHORT: reflect.TypeOf((*[]uint16)(nil)).Elem(), 741 TVLASHORT: reflect.TypeOf((*[]int16)(nil)).Elem(), 742 TVLAUINT: reflect.TypeOf((*[]uint32)(nil)).Elem(), 743 TVLAINT: reflect.TypeOf((*[]int32)(nil)).Elem(), 744 TVLAULONG: reflect.TypeOf((*[]uint64)(nil)).Elem(), 745 TVLALONG: reflect.TypeOf((*[]int64)(nil)).Elem(), 746 TVLAFLOAT: reflect.TypeOf((*[]float32)(nil)).Elem(), 747 TVLALONGLONG: reflect.TypeOf((*[]int64)(nil)).Elem(), 748 TVLADOUBLE: reflect.TypeOf((*[]float64)(nil)).Elem(), 749 TVLACOMPLEX: reflect.TypeOf((*[]complex64)(nil)).Elem(), 750 TVLADBLCOMPLEX: reflect.TypeOf((*[]complex128)(nil)).Elem(), 751 } 752 753 g_go2cfits = make(map[reflect.Type]TypeCode, len(g_cfits2go)) 754 for k, v := range g_cfits2go { 755 g_go2cfits[v] = k 756 } 757 } 758 759 // EOF