github.com/astrogo/fitsio@v0.3.0/column.go (about)

     1  // Copyright 2015 The astrogo Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fitsio
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  // Column represents a column in a FITS table
    16  type Column struct {
    17  	Name    string  // column name, corresponding to ``TTYPE`` keyword
    18  	Format  string  // column format, corresponding to ``TFORM`` keyword
    19  	Unit    string  // column unit, corresponding to ``TUNIT`` keyword
    20  	Null    string  // null value, corresponding to ``TNULL`` keyword
    21  	Bscale  float64 // bscale value, corresponding to ``TSCAL`` keyword
    22  	Bzero   float64 // bzero value, corresponding to ``TZERO`` keyword
    23  	Display string  // display format, corresponding to ``TDISP`` keyword
    24  	Dim     []int64 // column dimension corresponding to ``TDIM`` keyword
    25  	Start   int64   // column starting position, corresponding to ``TBCOL`` keyword
    26  
    27  	dtype  Type   // type of the value held by the column
    28  	offset int    // offset in bytes (from start of data-pad or heap-pad) to get at the column data
    29  	txtfmt string // go-based fmt string for ASCII table
    30  
    31  	// read function (binary/ascii)
    32  	read func(table *Table, icol int, irow int64, ptr interface{}) error
    33  
    34  	// write function (binary/ascii)
    35  	write func(table *Table, icol int, irow int64, ptr interface{}) error
    36  }
    37  
    38  // NewColumn creates a new Column with name `name` and Format inferred from the type of value
    39  func NewColumn(name string, v interface{}) (Column, error) {
    40  	panic("not implemented")
    41  }
    42  
    43  // Type returns the Go reflect.Type associated with this Column
    44  func (col *Column) Type() reflect.Type {
    45  	return col.dtype.gotype
    46  }
    47  
    48  // readBin reads the value at column number icol and row irow, into ptr.
    49  func (col *Column) readBin(table *Table, icol int, irow int64, ptr interface{}) error {
    50  	var err error
    51  
    52  	rv := reflect.Indirect(reflect.ValueOf(ptr))
    53  	rt := reflect.TypeOf(rv.Interface())
    54  
    55  	switch rt.Kind() {
    56  	case reflect.Slice:
    57  
    58  		beg := table.rowsz*int(irow) + col.offset
    59  		end := beg + col.dtype.dsize
    60  		row := table.data[beg:end]
    61  		r := newReader(row)
    62  		slice := reflect.ValueOf(ptr).Elem()
    63  		nmax := 0
    64  
    65  		switch col.dtype.dsize {
    66  		case 8:
    67  			var n int32
    68  			var offset int32
    69  			r.readI32(&n)
    70  			r.readI32(&offset)
    71  			beg = int(offset)
    72  			end = beg + int(n)*int(col.dtype.gotype.Elem().Size())
    73  			nmax = int(n)
    74  
    75  		case 16:
    76  			var n int64
    77  			var offset int64
    78  			r.readI64(&n)
    79  			r.readI64(&offset)
    80  			beg = int(offset)
    81  			end = beg + int(n)*int(col.dtype.gotype.Elem().Size())
    82  			nmax = int(n)
    83  		}
    84  		if slice.Len() < nmax {
    85  			slice = reflect.MakeSlice(rt, nmax, nmax)
    86  		}
    87  
    88  		r = newReader(table.heap[beg:end])
    89  		switch slice := slice.Interface().(type) {
    90  		case []bool:
    91  			r.readBools(slice[:nmax])
    92  
    93  		case []byte:
    94  			copy(slice[:nmax], r.p)
    95  
    96  		case []int8:
    97  			r.readI8s(slice[:nmax])
    98  
    99  		case []int16:
   100  			r.readI16s(slice[:nmax])
   101  
   102  		case []int32:
   103  			r.readI32s(slice[:nmax])
   104  
   105  		case []int64:
   106  			r.readI64s(slice[:nmax])
   107  
   108  		case []int:
   109  			r.readInts(slice[:nmax])
   110  
   111  		case []uint16:
   112  			r.readU16s(slice[:nmax])
   113  
   114  		case []uint32:
   115  			r.readU32s(slice[:nmax])
   116  
   117  		case []uint64:
   118  			r.readU64s(slice[:nmax])
   119  
   120  		case []uint:
   121  			r.readUints(slice[:nmax])
   122  
   123  		case []float32:
   124  			r.readF32s(slice[:nmax])
   125  
   126  		case []float64:
   127  			r.readF64s(slice[:nmax])
   128  
   129  		case []complex64:
   130  			r.readC64s(slice[:nmax])
   131  
   132  		case []complex128:
   133  			r.readC128s(slice[:nmax])
   134  
   135  		default:
   136  			panic(fmt.Errorf("fitsio: not implemented %T", slice))
   137  		}
   138  		rv.Set(slice)
   139  
   140  	case reflect.Array:
   141  
   142  		beg := table.rowsz*int(irow) + col.offset
   143  		end := beg + (col.dtype.dsize * col.dtype.len)
   144  		row := table.data[beg:end]
   145  		r := newReader(row)
   146  		switch slice := rv.Slice(0, rv.Len()).Interface().(type) {
   147  		case []bool:
   148  			r.readBools(slice)
   149  
   150  		case []byte:
   151  			copy(slice, r.p)
   152  
   153  		case []int8:
   154  			r.readI8s(slice)
   155  
   156  		case []int16:
   157  			r.readI16s(slice)
   158  
   159  		case []int32:
   160  			r.readI32s(slice)
   161  
   162  		case []int64:
   163  			r.readI64s(slice)
   164  
   165  		case []int:
   166  			r.readInts(slice)
   167  
   168  		case []uint16:
   169  			r.readU16s(slice)
   170  
   171  		case []uint32:
   172  			r.readU32s(slice)
   173  
   174  		case []uint64:
   175  			r.readU64s(slice)
   176  
   177  		case []uint:
   178  			r.readUints(slice)
   179  
   180  		case []float32:
   181  			r.readF32s(slice)
   182  
   183  		case []float64:
   184  			r.readF64s(slice)
   185  
   186  		case []complex64:
   187  			r.readC64s(slice)
   188  
   189  		case []complex128:
   190  			r.readC128s(slice)
   191  
   192  		default:
   193  			panic(fmt.Errorf("fitsio: not implemented %T", slice))
   194  		}
   195  
   196  	case reflect.Bool:
   197  
   198  		beg := table.rowsz*int(irow) + col.offset
   199  		end := beg + col.dtype.dsize
   200  
   201  		r := newReader(table.data[beg:end])
   202  		r.readBool(ptr.(*bool))
   203  
   204  	case reflect.Int8:
   205  
   206  		beg := table.rowsz*int(irow) + col.offset
   207  		end := beg + col.dtype.dsize
   208  
   209  		r := newReader(table.data[beg:end])
   210  		r.readI8(ptr.(*int8))
   211  
   212  	case reflect.Int16:
   213  
   214  		beg := table.rowsz*int(irow) + col.offset
   215  		end := beg + col.dtype.dsize
   216  
   217  		r := newReader(table.data[beg:end])
   218  		r.readI16(ptr.(*int16))
   219  
   220  	case reflect.Int32:
   221  
   222  		beg := table.rowsz*int(irow) + col.offset
   223  		end := beg + col.dtype.dsize
   224  
   225  		r := newReader(table.data[beg:end])
   226  		r.readI32(ptr.(*int32))
   227  
   228  	case reflect.Int64:
   229  
   230  		beg := table.rowsz*int(irow) + col.offset
   231  		end := beg + col.dtype.dsize
   232  
   233  		r := newReader(table.data[beg:end])
   234  		r.readI64(ptr.(*int64))
   235  
   236  	case reflect.Int:
   237  
   238  		beg := table.rowsz*int(irow) + col.offset
   239  		end := beg + col.dtype.dsize
   240  
   241  		r := newReader(table.data[beg:end])
   242  		r.readInt(ptr.(*int))
   243  
   244  	case reflect.Uint8:
   245  
   246  		beg := table.rowsz*int(irow) + col.offset
   247  		end := beg + col.dtype.dsize
   248  
   249  		r := newReader(table.data[beg:end])
   250  		r.readU8(ptr.(*uint8))
   251  
   252  	case reflect.Uint16:
   253  
   254  		beg := table.rowsz*int(irow) + col.offset
   255  		end := beg + col.dtype.dsize
   256  
   257  		r := newReader(table.data[beg:end])
   258  		r.readU16(ptr.(*uint16))
   259  
   260  	case reflect.Uint32:
   261  
   262  		beg := table.rowsz*int(irow) + col.offset
   263  		end := beg + col.dtype.dsize
   264  
   265  		r := newReader(table.data[beg:end])
   266  		r.readU32(ptr.(*uint32))
   267  
   268  	case reflect.Uint64:
   269  
   270  		beg := table.rowsz*int(irow) + col.offset
   271  		end := beg + col.dtype.dsize
   272  
   273  		r := newReader(table.data[beg:end])
   274  		r.readU64(ptr.(*uint64))
   275  
   276  	case reflect.Uint:
   277  
   278  		beg := table.rowsz*int(irow) + col.offset
   279  		end := beg + col.dtype.dsize
   280  
   281  		r := newReader(table.data[beg:end])
   282  		r.readUint(ptr.(*uint))
   283  
   284  	case reflect.Float32:
   285  
   286  		beg := table.rowsz*int(irow) + col.offset
   287  		end := beg + col.dtype.dsize
   288  
   289  		r := newReader(table.data[beg:end])
   290  		r.readF32(ptr.(*float32))
   291  
   292  	case reflect.Float64:
   293  
   294  		beg := table.rowsz*int(irow) + col.offset
   295  		end := beg + col.dtype.dsize
   296  
   297  		r := newReader(table.data[beg:end])
   298  		r.readF64(ptr.(*float64))
   299  
   300  	case reflect.Complex64:
   301  
   302  		beg := table.rowsz*int(irow) + col.offset
   303  		end := beg + col.dtype.dsize
   304  
   305  		r := newReader(table.data[beg:end])
   306  		r.readC64(ptr.(*complex64))
   307  
   308  	case reflect.Complex128:
   309  
   310  		beg := table.rowsz*int(irow) + col.offset
   311  		end := beg + col.dtype.dsize
   312  
   313  		r := newReader(table.data[beg:end])
   314  		r.readC128(ptr.(*complex128))
   315  
   316  	case reflect.String:
   317  
   318  		beg := table.rowsz*int(irow) + col.offset
   319  		end := beg + col.dtype.dsize
   320  		row := table.data[beg:end]
   321  		str := ""
   322  		if row[0] == '\x00' {
   323  			str = string(row[1:])
   324  			str = strings.TrimRight(str, string([]byte("\x00")))
   325  		} else {
   326  			str = string(row)
   327  		}
   328  
   329  		rv.SetString(str)
   330  
   331  	default:
   332  		return fmt.Errorf("fitsio: binary-table can not read/write %v", rt.Kind())
   333  	}
   334  	return err
   335  }
   336  
   337  // writeBin writes the value at column number icol and row irow, from ptr.
   338  func (col *Column) writeBin(table *Table, icol int, irow int64, ptr interface{}) error {
   339  	var (
   340  		err error
   341  		rv  = reflect.Indirect(reflect.ValueOf(ptr))
   342  		rvi = rv.Interface()
   343  		rt  = reflect.TypeOf(rvi)
   344  	)
   345  
   346  	switch rt.Kind() {
   347  	case reflect.Slice:
   348  
   349  		beg := table.rowsz*int(irow) + col.offset
   350  		end := beg + col.dtype.dsize
   351  
   352  		w := newWriter(table.data[beg:end])
   353  		nmax := rv.Len()
   354  
   355  		switch col.dtype.dsize {
   356  		case 8:
   357  			w.writeI32(int32(nmax))
   358  			w.writeI32(int32(len(table.heap)))
   359  
   360  		case 16:
   361  			w.writeI64(int64(nmax))
   362  			w.writeI64(int64(len(table.heap)))
   363  		}
   364  
   365  		{
   366  			w := newWriter(make([]byte, nmax*col.dtype.hsize))
   367  			switch slice := rvi.(type) {
   368  			case []bool:
   369  				w.writeBools(slice)
   370  
   371  			case []byte:
   372  				copy(w.p, slice)
   373  
   374  			case []int8:
   375  				w.writeI8s(slice)
   376  
   377  			case []int16:
   378  				w.writeI16s(slice)
   379  
   380  			case []int32:
   381  				w.writeI32s(slice)
   382  
   383  			case []int64:
   384  				w.writeI64s(slice)
   385  
   386  			case []int:
   387  				w.writeInts(slice)
   388  
   389  			case []uint16:
   390  				w.writeU16s(slice)
   391  
   392  			case []uint32:
   393  				w.writeU32s(slice)
   394  
   395  			case []uint64:
   396  				w.writeU64s(slice)
   397  
   398  			case []uint:
   399  				w.writeUints(slice)
   400  
   401  			case []float32:
   402  				w.writeF32s(slice)
   403  
   404  			case []float64:
   405  				w.writeF64s(slice)
   406  
   407  			case []complex64:
   408  				w.writeC64s(slice)
   409  
   410  			case []complex128:
   411  				w.writeC128s(slice)
   412  
   413  			default:
   414  				panic(fmt.Errorf("fitsio: not implemented %T", slice))
   415  			}
   416  			table.heap = append(table.heap, w.bytes()...)
   417  		}
   418  
   419  	case reflect.Array:
   420  
   421  		beg := table.rowsz*int(irow) + col.offset
   422  		end := beg + (col.dtype.dsize * col.dtype.len)
   423  
   424  		w := newWriter(table.data[beg:end])
   425  		switch slice := rv.Slice(0, rv.Len()).Interface().(type) {
   426  		case []bool:
   427  			w.writeBools(slice)
   428  
   429  		case []byte:
   430  			copy(w.p, slice)
   431  
   432  		case []int8:
   433  			w.writeI8s(slice)
   434  
   435  		case []int16:
   436  			w.writeI16s(slice)
   437  
   438  		case []int32:
   439  			w.writeI32s(slice)
   440  
   441  		case []int64:
   442  			w.writeI64s(slice)
   443  
   444  		case []int:
   445  			w.writeInts(slice)
   446  
   447  		case []uint16:
   448  			w.writeU16s(slice)
   449  
   450  		case []uint32:
   451  			w.writeU32s(slice)
   452  
   453  		case []uint64:
   454  			w.writeU64s(slice)
   455  
   456  		case []uint:
   457  			w.writeUints(slice)
   458  
   459  		case []float32:
   460  			w.writeF32s(slice)
   461  
   462  		case []float64:
   463  			w.writeF64s(slice)
   464  
   465  		case []complex64:
   466  			w.writeC64s(slice)
   467  
   468  		case []complex128:
   469  			w.writeC128s(slice)
   470  
   471  		default:
   472  			panic(fmt.Errorf("fitsio: not implemented %T", slice))
   473  		}
   474  
   475  	case reflect.Bool:
   476  
   477  		beg := table.rowsz*int(irow) + col.offset
   478  		end := beg + col.dtype.dsize
   479  
   480  		w := newWriter(table.data[beg:end])
   481  		w.writeBool(rvi.(bool))
   482  
   483  	case reflect.Int8:
   484  
   485  		beg := table.rowsz*int(irow) + col.offset
   486  		end := beg + col.dtype.dsize
   487  
   488  		w := newWriter(table.data[beg:end])
   489  		w.writeI8(rvi.(int8))
   490  
   491  	case reflect.Int16:
   492  
   493  		beg := table.rowsz*int(irow) + col.offset
   494  		end := beg + col.dtype.dsize
   495  
   496  		w := newWriter(table.data[beg:end])
   497  		w.writeI16(rvi.(int16))
   498  
   499  	case reflect.Int32:
   500  
   501  		beg := table.rowsz*int(irow) + col.offset
   502  		end := beg + col.dtype.dsize
   503  
   504  		w := newWriter(table.data[beg:end])
   505  		w.writeI32(rvi.(int32))
   506  
   507  	case reflect.Int64:
   508  
   509  		beg := table.rowsz*int(irow) + col.offset
   510  		end := beg + col.dtype.dsize
   511  
   512  		w := newWriter(table.data[beg:end])
   513  		w.writeI64(rvi.(int64))
   514  
   515  	case reflect.Int:
   516  
   517  		beg := table.rowsz*int(irow) + col.offset
   518  		end := beg + col.dtype.dsize
   519  
   520  		w := newWriter(table.data[beg:end])
   521  		w.writeInt(rvi.(int))
   522  
   523  	case reflect.Uint8:
   524  
   525  		beg := table.rowsz*int(irow) + col.offset
   526  		end := beg + col.dtype.dsize
   527  
   528  		w := newWriter(table.data[beg:end])
   529  		w.writeU8(rvi.(uint8))
   530  
   531  	case reflect.Uint16:
   532  
   533  		beg := table.rowsz*int(irow) + col.offset
   534  		end := beg + col.dtype.dsize
   535  
   536  		w := newWriter(table.data[beg:end])
   537  		w.writeU16(rvi.(uint16))
   538  
   539  	case reflect.Uint32:
   540  
   541  		beg := table.rowsz*int(irow) + col.offset
   542  		end := beg + col.dtype.dsize
   543  
   544  		w := newWriter(table.data[beg:end])
   545  		w.writeU32(rvi.(uint32))
   546  
   547  	case reflect.Uint64:
   548  
   549  		beg := table.rowsz*int(irow) + col.offset
   550  		end := beg + col.dtype.dsize
   551  
   552  		w := newWriter(table.data[beg:end])
   553  		w.writeU64(rvi.(uint64))
   554  
   555  	case reflect.Uint:
   556  
   557  		beg := table.rowsz*int(irow) + col.offset
   558  		end := beg + col.dtype.dsize
   559  
   560  		w := newWriter(table.data[beg:end])
   561  		w.writeUint(rvi.(uint))
   562  
   563  	case reflect.Float32:
   564  
   565  		beg := table.rowsz*int(irow) + col.offset
   566  		end := beg + col.dtype.dsize
   567  
   568  		w := newWriter(table.data[beg:end])
   569  		w.writeF32(rvi.(float32))
   570  
   571  	case reflect.Float64:
   572  
   573  		beg := table.rowsz*int(irow) + col.offset
   574  		end := beg + col.dtype.dsize
   575  
   576  		w := newWriter(table.data[beg:end])
   577  		w.writeF64(rvi.(float64))
   578  
   579  	case reflect.Complex64:
   580  
   581  		beg := table.rowsz*int(irow) + col.offset
   582  		end := beg + col.dtype.dsize
   583  
   584  		w := newWriter(table.data[beg:end])
   585  		w.writeC64(rvi.(complex64))
   586  
   587  	case reflect.Complex128:
   588  
   589  		beg := table.rowsz*int(irow) + col.offset
   590  		end := beg + col.dtype.dsize
   591  
   592  		w := newWriter(table.data[beg:end])
   593  		w.writeC128(rvi.(complex128))
   594  
   595  	case reflect.String:
   596  
   597  		beg := table.rowsz*int(irow) + col.offset
   598  		end := beg + col.dtype.dsize
   599  
   600  		buf := newWriter(table.data[beg:end])
   601  		str := rv.String()
   602  		data := make([]byte, 0, len(str)+1)
   603  		data = append(data, '\x00')
   604  		data = append(data, []byte(str)...)
   605  		n := len(data)
   606  		if n > end-beg {
   607  			n = end - beg
   608  		}
   609  		if n < end-beg {
   610  			data = append(data, bytes.Repeat([]byte("\x00"), end-beg-n)...)
   611  			n = len(data)
   612  		}
   613  		_, err = buf.Write(data[:n])
   614  
   615  		if err != nil {
   616  			return fmt.Errorf("fitsio: %v\n", err)
   617  		}
   618  
   619  	default:
   620  		return fmt.Errorf("fitsio: binary-table can not read/write %v", rt.Kind())
   621  	}
   622  
   623  	return err
   624  }
   625  
   626  // readTxt reads the value at column number icol and row irow, into ptr.
   627  func (col *Column) readTxt(table *Table, icol int, irow int64, ptr interface{}) error {
   628  	var err error
   629  
   630  	rv := reflect.Indirect(reflect.ValueOf(ptr))
   631  	rt := reflect.TypeOf(rv.Interface())
   632  
   633  	beg := table.rowsz*int(irow) + col.offset
   634  	end := beg + col.dtype.dsize
   635  	buf := table.data[beg:end]
   636  	str := strings.TrimSpace(string(buf))
   637  
   638  	switch rt.Kind() {
   639  	case reflect.Slice:
   640  
   641  		return fmt.Errorf("fitsio: ASCII-table can not read/write slices")
   642  
   643  	case reflect.Array:
   644  
   645  		return fmt.Errorf("fitsio: ASCII-table can not read/write arrays")
   646  
   647  	case reflect.Bool:
   648  
   649  		return fmt.Errorf("fitsio: ASCII-table can not read/write booleans")
   650  
   651  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   652  		v, err := strconv.ParseUint(str, 10, 64)
   653  		if err != nil {
   654  			return fmt.Errorf("fitsio: error parsing %q into a uint: %v", str, err)
   655  		}
   656  		rv.SetUint(v)
   657  
   658  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   659  		v, err := strconv.ParseInt(str, 10, 64)
   660  		if err != nil {
   661  			return fmt.Errorf("fitsio: error parsing %q into an int: %v", str, err)
   662  		}
   663  		rv.SetInt(v)
   664  
   665  	case reflect.Float32, reflect.Float64:
   666  
   667  		v, err := strconv.ParseFloat(str, 64)
   668  		if err != nil {
   669  			return fmt.Errorf("fitsio: error parsing %q into a float: %v", str, err)
   670  		}
   671  		rv.SetFloat(v)
   672  
   673  	case reflect.Complex64, reflect.Complex128:
   674  
   675  		return fmt.Errorf("fitsio: ASCII-table can not read/write complexes")
   676  
   677  	case reflect.String:
   678  		rv.SetString(str)
   679  
   680  	default:
   681  		return fmt.Errorf("fitsio: ASCII-table can not read/write %v", rt.Kind())
   682  	}
   683  	return err
   684  }
   685  
   686  // writeTxt writes the value at column number icol and row irow, from ptr.
   687  func (col *Column) writeTxt(table *Table, icol int, irow int64, ptr interface{}) error {
   688  	var err error
   689  
   690  	beg := table.rowsz*int(irow) + col.offset
   691  	end := beg + col.dtype.dsize
   692  	w := newWriter(table.data[beg:end])
   693  
   694  	rv := reflect.Indirect(reflect.ValueOf(ptr))
   695  	rt := reflect.TypeOf(rv.Interface())
   696  
   697  	switch rt.Kind() {
   698  	case reflect.Slice:
   699  
   700  		return fmt.Errorf("fitsio: ASCII-table can not read/write slices")
   701  
   702  	case reflect.Array:
   703  
   704  		return fmt.Errorf("fitsio: ASCII-table can not read/write arrays")
   705  
   706  	case reflect.Bool:
   707  
   708  		return fmt.Errorf("fitsio: ASCII-table can not read/write booleans")
   709  
   710  	case reflect.Complex64, reflect.Complex128:
   711  
   712  		return fmt.Errorf("fitsio: ASCII-table can not read/write complexes")
   713  
   714  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
   715  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   716  		reflect.Float32, reflect.Float64,
   717  		reflect.String:
   718  
   719  		str := fmt.Sprintf(col.txtfmt, rv.Interface())
   720  		n := 0
   721  		n, err = fmt.Fprintf(w, str)
   722  		if err != nil {
   723  			return fmt.Errorf("fitsio: error writing '%#v': %v", rv.Interface(), err)
   724  		}
   725  		if n != len(w.p) {
   726  			return fmt.Errorf(
   727  				"fitsio: error writing '%#v'. expected %d bytes. wrote %d",
   728  				rv.Interface(), len(w.p), n,
   729  			)
   730  		}
   731  
   732  	default:
   733  		return fmt.Errorf("fitsio: ASCII-table can not read/write %v", rt.Kind())
   734  	}
   735  
   736  	return err
   737  }