1#import "CPTNumericData.h"
2#import "CPTNumericData+TypeConversion.h"
3#import "CPTMutableNumericData.h"
4#import "CPTExceptions.h"
5#import "CPTUtilities.h"
6#import "complex.h"
7
8/**	@cond */
9@interface CPTNumericData()
10
11-(void)commonInitWithData:(NSData *)newData
12				 dataType:(CPTNumericDataType)newDataType
13                    shape:(NSArray *)shapeArray;
14
15-(NSData *)dataFromArray:(NSArray *)newData dataType:(CPTNumericDataType)newDataType;
16
17@end
18/**	@endcond */
19
20#pragma mark -
21
22/** @brief An annotated NSData type.
23 *
24 *	CPTNumericData combines a data buffer with information
25 *	about the data (shape, data type, size, etc.).
26 *	The data is assumed to be an array of one or more dimensions
27 *	of a single type of numeric data. Each numeric value in the array,
28 *	which can be more than one byte in size, is referred to as a "sample".
29 *	The structure of this object is similar to the NumPy ndarray
30 *	object.
31 *
32 *	The supported data types are:
33 *	- 1, 2, 4, and 8-byte signed integers
34 *	- 1, 2, 4, and 8-byte unsigned integers
35 *	- <code>float</code> and <code>double</code> floating point numbers
36 *	- <code>float complex</code> and <code>double complex</code> floating point complex numbers
37 *	- NSDecimal base-10 numbers
38 *
39 *	All integer and floating point types can be represented using big endian or little endian
40 *	byte order. Complex and decimal types support only the the host system's native byte order.
41 **/
42@implementation CPTNumericData
43
44/** @property data
45 *	@brief The data buffer.
46 **/
47@synthesize data;
48
49/** @property bytes
50 *	@brief Returns a pointer to the data buffer’s contents.
51 **/
52@dynamic bytes;
53
54/** @property length
55 *	@brief Returns the number of bytes contained in the data buffer.
56 **/
57@dynamic length;
58
59/** @property dataType
60 *	@brief The type of data stored in the data buffer.
61 **/
62@synthesize dataType;
63
64/** @property dataTypeFormat
65 *	@brief The format of the data stored in the data buffer.
66 **/
67@dynamic dataTypeFormat;
68
69/** @property sampleBytes
70 *	@brief The number of bytes in a single sample of data.
71 **/
72@dynamic sampleBytes;
73
74/** @property byteOrder
75 *	@brief The byte order used to store each sample in the data buffer.
76 **/
77@dynamic byteOrder;
78
79/** @property shape
80 *	@brief The shape of the data buffer array.
81 *
82 *	The shape describes the dimensions of the sample array stored in
83 *	the data buffer. Each entry in the shape array represents the
84 *	size of the corresponding array dimension and should be an unsigned
85 *	integer encoded in an instance of NSNumber.
86 **/
87@synthesize shape;
88
89/** @property numberOfDimensions
90 *	@brief The number dimensions in the data buffer array.
91 **/
92@dynamic numberOfDimensions;
93
94/** @property numberOfSamples
95 *	@brief The number of samples of dataType stored in the data buffer.
96 **/
97@dynamic numberOfSamples;
98
99#pragma mark -
100#pragma mark Factory Methods
101
102/** @brief Creates and returns a new CPTNumericData instance.
103 *	@param newData The data buffer.
104 *	@param newDataType The type of data stored in the buffer.
105 *	@param shapeArray The shape of the data buffer array.
106 *  @return A new CPTNumericData instance.
107 **/
108+(CPTNumericData *)numericDataWithData:(NSData *)newData
109							 dataType:(CPTNumericDataType)newDataType
110                                shape:(NSArray *)shapeArray
111{
112    return [[[CPTNumericData alloc] initWithData:newData
113									   dataType:newDataType
114                                          shape:shapeArray]
115            autorelease];
116}
117
118/** @brief Creates and returns a new CPTNumericData instance.
119 *	@param newData The data buffer.
120 *	@param newDataTypeString The type of data stored in the buffer.
121 *	@param shapeArray The shape of the data buffer array.
122 *  @return A new CPTNumericData instance.
123 **/
124+(CPTNumericData *)numericDataWithData:(NSData *)newData
125					   dataTypeString:(NSString *)newDataTypeString
126                                shape:(NSArray *)shapeArray
127{
128    return [[[CPTNumericData alloc] initWithData:newData
129									   dataType:CPTDataTypeWithDataTypeString(newDataTypeString)
130                                          shape:shapeArray]
131            autorelease];
132}
133
134/** @brief Creates and returns a new CPTNumericData instance.
135 *
136 *	Objects in newData should be instances of NSNumber, NSDecimalNumber, NSString, or NSNull.
137 *	Numbers and strings will be converted to newDataType and stored in the receiver.
138 *	Any instances of NSNull will be treated as "not a number" (NAN) values for floating point types and "0" for integer types.
139 *	@param newData An array of numbers.
140 *	@param newDataType The type of data stored in the buffer.
141 *	@param shapeArray The shape of the data buffer array.
142 *  @return A new CPTNumericData instance.
143 **/
144+(CPTNumericData *)numericDataWithArray:(NSArray *)newData
145							  dataType:(CPTNumericDataType)newDataType
146								 shape:(NSArray *)shapeArray
147{
148    return [[[CPTNumericData alloc] initWithArray:newData
149										dataType:newDataType
150										   shape:shapeArray]
151            autorelease];
152}
153
154/** @brief Creates and returns a new CPTNumericData instance.
155 *
156 *	Objects in newData should be instances of NSNumber, NSDecimalNumber, NSString, or NSNull.
157 *	Numbers and strings will be converted to newDataTypeString and stored in the receiver.
158 *	Any instances of NSNull will be treated as "not a number" (NAN) values for floating point types and "0" for integer types.
159 *	@param newData An array of numbers.
160 *	@param newDataTypeString The type of data stored in the buffer.
161 *	@param shapeArray The shape of the data buffer array.
162 *  @return A new CPTNumericData instance.
163 **/
164+(CPTNumericData *)numericDataWithArray:(NSArray *)newData
165						dataTypeString:(NSString *)newDataTypeString
166								 shape:(NSArray *)shapeArray
167{
168    return [[[CPTNumericData alloc] initWithArray:newData
169										dataType:CPTDataTypeWithDataTypeString(newDataTypeString)
170										   shape:shapeArray]
171            autorelease];
172}
173
174#pragma mark -
175#pragma mark Init/Dealloc
176
177/** @brief Initializes a newly allocated CPTNumericData object with the provided data. This is the designated initializer.
178 *	@param newData The data buffer.
179 *	@param newDataType The type of data stored in the buffer.
180 *	@param shapeArray The shape of the data buffer array.
181 *  @return The initialized CPTNumericData instance.
182 **/
183-(id)initWithData:(NSData *)newData
184		 dataType:(CPTNumericDataType)newDataType
185            shape:(NSArray *)shapeArray
186{
187    if ( (self = [super init]) ) {
188        [self commonInitWithData:newData
189						dataType:newDataType
190                           shape:shapeArray];
191    }
192
193    return self;
194}
195
196/** @brief Initializes a newly allocated CPTNumericData object with the provided data.
197 *	@param newData The data buffer.
198 *	@param newDataTypeString The type of data stored in the buffer.
199 *	@param shapeArray The shape of the data buffer array.
200 *  @return The initialized CPTNumericData instance.
201 **/
202-(id)initWithData:(NSData *)newData
203   dataTypeString:(NSString *)newDataTypeString
204            shape:(NSArray *)shapeArray
205{
206    return [self initWithData:newData
207					 dataType:CPTDataTypeWithDataTypeString(newDataTypeString)
208                        shape:shapeArray];
209}
210
211/** @brief Initializes a newly allocated CPTNumericData object with the provided data.
212 *
213 *	Objects in newData should be instances of NSNumber, NSDecimalNumber, NSString, or NSNull.
214 *	Numbers and strings will be converted to newDataType and stored in the receiver.
215 *	Any instances of NSNull will be treated as "not a number" (NAN) values for floating point types and "0" for integer types.
216 *	@param newData An array of numbers.
217 *	@param newDataType The type of data stored in the buffer.
218 *	@param shapeArray The shape of the data buffer array.
219 *  @return The initialized CPTNumericData instance.
220 **/
221-(id)initWithArray:(NSArray *)newData
222		  dataType:(CPTNumericDataType)newDataType
223			 shape:(NSArray *)shapeArray
224{
225    return [self initWithData:[self dataFromArray:newData dataType:newDataType]
226					 dataType:newDataType
227                        shape:shapeArray];
228}
229
230/** @brief Initializes a newly allocated CPTNumericData object with the provided data.
231 *
232 *	Objects in newData should be instances of NSNumber, NSDecimalNumber, NSString, or NSNull.
233 *	Numbers and strings will be converted to newDataTypeString and stored in the receiver.
234 *	Any instances of NSNull will be treated as "not a number" (NAN) values for floating point types and "0" for integer types.
235 *	@param newData An array of numbers.
236 *	@param newDataTypeString The type of data stored in the buffer.
237 *	@param shapeArray The shape of the data buffer array.
238 *  @return The initialized CPTNumericData instance.
239 **/
240-(id)initWithArray:(NSArray *)newData
241	dataTypeString:(NSString *)newDataTypeString
242			 shape:(NSArray *)shapeArray
243{
244    return [self initWithArray:newData
245					  dataType:CPTDataTypeWithDataTypeString(newDataTypeString)
246						 shape:shapeArray];
247}
248
249-(void)commonInitWithData:(NSData *)newData
250				 dataType:(CPTNumericDataType)newDataType
251                    shape:(NSArray *)shapeArray
252{
253	NSParameterAssert(CPTDataTypeIsSupported(newDataType));
254
255    data = [newData copy];
256    dataType = newDataType;
257
258    if ( shapeArray == nil ) {
259        shape = [[NSArray arrayWithObject:[NSNumber numberWithUnsignedInteger:self.numberOfSamples]] retain];
260    }
261	else {
262        NSUInteger prod = 1;
263        for ( NSNumber *cNum in shapeArray ) {
264            prod *= [cNum unsignedIntegerValue];
265        }
266
267        if ( prod != self.numberOfSamples ) {
268            [NSException raise:CPTNumericDataException
269                        format:@"Shape product (%u) does not match data size (%u)", prod, self.numberOfSamples];
270        }
271
272        shape = [shapeArray copy];
273    }
274}
275
276-(void)dealloc
277{
278    [data release];
279    [shape release];
280
281    [super dealloc];
282}
283
284#pragma mark -
285#pragma mark Accessors
286
287-(NSUInteger)numberOfDimensions
288{
289    return self.shape.count;
290}
291
292-(const void *)bytes
293{
294    return self.data.bytes;
295}
296
297-(NSUInteger)length
298{
299    return self.data.length;
300}
301
302-(NSUInteger)numberOfSamples
303{
304    return (self.length / self.dataType.sampleBytes);
305}
306
307-(CPTDataTypeFormat)dataTypeFormat
308{
309    return self.dataType.dataTypeFormat;
310}
311
312-(size_t)sampleBytes
313{
314    return self.dataType.sampleBytes;
315}
316
317-(CFByteOrder)byteOrder
318{
319    return self.dataType.byteOrder;
320}
321
322#pragma mark -
323#pragma mark Samples
324
325/**	@brief Gets the value of a given sample in the data buffer.
326 *	@param sample The index into the sample array. The array is treated as if it only has one dimension.
327 *	@return The sample value wrapped in an instance of NSNumber or <code>nil</code> if the sample index is out of bounds.
328 *
329 *	NSNumber does not support complex numbers. Complex number types will be cast to
330 *	<code>float</code> or <code>double</code> before being wrapped in an instance of NSNumber.
331 **/
332-(NSNumber *)sampleValue:(NSUInteger)sample
333{
334    NSNumber *result = nil;
335
336	if ( sample < self.numberOfSamples ) {
337		// Code generated with "CPTNumericData+TypeConversions_Generation.py"
338		// ========================================================================
339
340		switch ( self.dataTypeFormat ) {
341			case CPTUndefinedDataType:
342				[NSException raise:NSInvalidArgumentException format:@"Unsupported data type (CPTUndefinedDataType)"];
343				break;
344			case CPTIntegerDataType:
345				switch ( self.sampleBytes ) {
346					case sizeof(int8_t):
347						result = [NSNumber numberWithChar:*(int8_t *)[self samplePointer:sample]];
348						break;
349					case sizeof(int16_t):
350						result = [NSNumber numberWithShort:*(int16_t *)[self samplePointer:sample]];
351						break;
352					case sizeof(int32_t):
353						result = [NSNumber numberWithLong:*(int32_t *)[self samplePointer:sample]];
354						break;
355					case sizeof(int64_t):
356						result = [NSNumber numberWithLongLong:*(int64_t *)[self samplePointer:sample]];
357						break;
358				}
359				break;
360			case CPTUnsignedIntegerDataType:
361				switch ( self.sampleBytes ) {
362					case sizeof(uint8_t):
363						result = [NSNumber numberWithUnsignedChar:*(uint8_t *)[self samplePointer:sample]];
364						break;
365					case sizeof(uint16_t):
366						result = [NSNumber numberWithUnsignedShort:*(uint16_t *)[self samplePointer:sample]];
367						break;
368					case sizeof(uint32_t):
369						result = [NSNumber numberWithUnsignedLong:*(uint32_t *)[self samplePointer:sample]];
370						break;
371					case sizeof(uint64_t):
372						result = [NSNumber numberWithUnsignedLongLong:*(uint64_t *)[self samplePointer:sample]];
373						break;
374				}
375				break;
376			case CPTFloatingPointDataType:
377				switch ( self.sampleBytes ) {
378					case sizeof(float):
379						result = [NSNumber numberWithFloat:*(float *)[self samplePointer:sample]];
380						break;
381					case sizeof(double):
382						result = [NSNumber numberWithDouble:*(double *)[self samplePointer:sample]];
383						break;
384				}
385				break;
386			case CPTComplexFloatingPointDataType:
387				switch ( self.sampleBytes ) {
388					case sizeof(float complex):
389						result = [NSNumber numberWithFloat:*(float complex *)[self samplePointer:sample]];
390						break;
391					case sizeof(double complex):
392						result = [NSNumber numberWithDouble:*(double complex *)[self samplePointer:sample]];
393						break;
394				}
395				break;
396			case CPTDecimalDataType:
397				switch ( self.sampleBytes ) {
398					case sizeof(NSDecimal):
399						result = [NSDecimalNumber decimalNumberWithDecimal:*(NSDecimal *)[self samplePointer:sample]];
400						break;
401				}
402				break;
403		}
404
405		// End of code generated with "CPTNumericData+TypeConversions_Generation.py"
406		// ========================================================================
407	}
408
409    return result;
410}
411
412/**	@brief Gets a pointer to a given sample in the data buffer.
413 *	@param sample The index into the sample array. The array is treated as if it only has one dimension.
414 *	@return A pointer to the sample or <code>NULL</code> if the sample index is out of bounds.
415 **/
416-(void *)samplePointer:(NSUInteger)sample
417{
418	if ( sample < self.numberOfSamples ) {
419		return (void *) ((char *)self.bytes + sample * self.sampleBytes);
420	}
421	else {
422		return NULL;
423	}
424}
425
426/**	@brief Gets an array data samples from the receiver.
427 *	@return An NSArray of NSNumber objects representing the data from the receiver.
428 **/
429-(NSArray *)sampleArray
430{
431	NSUInteger sampleCount = self.numberOfSamples;
432	NSMutableArray *samples = [[NSMutableArray alloc] initWithCapacity:sampleCount];
433
434	for ( NSUInteger i = 0; i < sampleCount; i++ ) {
435		[samples addObject:[self sampleValue:i]];
436	}
437
438	NSArray *result = [NSArray arrayWithArray:samples];
439	[samples release];
440
441	return result;
442}
443
444-(NSData *)dataFromArray:(NSArray *)newData dataType:(CPTNumericDataType)newDataType
445{
446	NSParameterAssert(CPTDataTypeIsSupported(newDataType));
447	NSParameterAssert(newDataType.dataTypeFormat != CPTUndefinedDataType);
448	NSParameterAssert(newDataType.dataTypeFormat != CPTComplexFloatingPointDataType);
449
450	NSMutableData *sampleData = [[NSMutableData alloc] initWithLength:newData.count * newDataType.sampleBytes];
451
452	// Code generated with "CPTNumericData+TypeConversions_Generation.py"
453	// ========================================================================
454
455	switch ( newDataType.dataTypeFormat ) {
456		case CPTUndefinedDataType:
457			// Unsupported
458			break;
459		case CPTIntegerDataType:
460			switch ( newDataType.sampleBytes ) {
461				case sizeof(int8_t): {
462					int8_t *toBytes = (int8_t *)sampleData.mutableBytes;
463					for ( id sample in newData ) {
464						if ( [sample respondsToSelector:@selector(charValue)] ) {
465							*toBytes++ = (int8_t)[(NSNumber *)sample charValue];
466						}
467						else {
468							*toBytes++ = 0;
469						}
470					}
471				}
472					break;
473				case sizeof(int16_t): {
474					int16_t *toBytes = (int16_t *)sampleData.mutableBytes;
475					for ( id sample in newData ) {
476						if ( [sample respondsToSelector:@selector(shortValue)] ) {
477							*toBytes++ = (int16_t)[(NSNumber *)sample shortValue];
478						}
479						else {
480							*toBytes++ = 0;
481						}
482					}
483				}
484					break;
485				case sizeof(int32_t): {
486					int32_t *toBytes = (int32_t *)sampleData.mutableBytes;
487					for ( id sample in newData ) {
488						if ( [sample respondsToSelector:@selector(longValue)] ) {
489							*toBytes++ = (int32_t)[(NSNumber *)sample longValue];
490						}
491						else {
492							*toBytes++ = 0;
493						}
494					}
495				}
496					break;
497				case sizeof(int64_t): {
498					int64_t *toBytes = (int64_t *)sampleData.mutableBytes;
499					for ( id sample in newData ) {
500						if ( [sample respondsToSelector:@selector(longLongValue)] ) {
501							*toBytes++ = (int64_t)[(NSNumber *)sample longLongValue];
502						}
503						else {
504							*toBytes++ = 0;
505						}
506					}
507				}
508					break;
509			}
510			break;
511		case CPTUnsignedIntegerDataType:
512			switch ( newDataType.sampleBytes ) {
513				case sizeof(uint8_t): {
514					uint8_t *toBytes = (uint8_t *)sampleData.mutableBytes;
515					for ( id sample in newData ) {
516						if ( [sample respondsToSelector:@selector(unsignedCharValue)] ) {
517							*toBytes++ = (uint8_t)[(NSNumber *)sample unsignedCharValue];
518						}
519						else {
520							*toBytes++ = 0;
521						}
522					}
523				}
524					break;
525				case sizeof(uint16_t): {
526					uint16_t *toBytes = (uint16_t *)sampleData.mutableBytes;
527					for ( id sample in newData ) {
528						if ( [sample respondsToSelector:@selector(unsignedShortValue)] ) {
529							*toBytes++ = (uint16_t)[(NSNumber *)sample unsignedShortValue];
530						}
531						else {
532							*toBytes++ = 0;
533						}
534					}
535				}
536					break;
537				case sizeof(uint32_t): {
538					uint32_t *toBytes = (uint32_t *)sampleData.mutableBytes;
539					for ( id sample in newData ) {
540						if ( [sample respondsToSelector:@selector(unsignedLongValue)] ) {
541							*toBytes++ = (uint32_t)[(NSNumber *)sample unsignedLongValue];
542						}
543						else {
544							*toBytes++ = 0;
545						}
546					}
547				}
548					break;
549				case sizeof(uint64_t): {
550					uint64_t *toBytes = (uint64_t *)sampleData.mutableBytes;
551					for ( id sample in newData ) {
552						if ( [sample respondsToSelector:@selector(unsignedLongLongValue)] ) {
553							*toBytes++ = (uint64_t)[(NSNumber *)sample unsignedLongLongValue];
554						}
555						else {
556							*toBytes++ = 0;
557						}
558					}
559				}
560					break;
561			}
562			break;
563		case CPTFloatingPointDataType:
564			switch ( newDataType.sampleBytes ) {
565				case sizeof(float): {
566					float *toBytes = (float *)sampleData.mutableBytes;
567					for ( id sample in newData ) {
568						if ( [sample respondsToSelector:@selector(floatValue)] ) {
569							*toBytes++ = (float)[(NSNumber *)sample floatValue];
570						}
571						else {
572							*toBytes++ = NAN;
573						}
574					}
575				}
576					break;
577				case sizeof(double): {
578					double *toBytes = (double *)sampleData.mutableBytes;
579					for ( id sample in newData ) {
580						if ( [sample respondsToSelector:@selector(doubleValue)] ) {
581							*toBytes++ = (double)[(NSNumber *)sample doubleValue];
582						}
583						else {
584							*toBytes++ = NAN;
585						}
586					}
587				}
588					break;
589			}
590			break;
591		case CPTComplexFloatingPointDataType:
592			switch ( newDataType.sampleBytes ) {
593				case sizeof(float complex): {
594					float complex *toBytes = (float complex *)sampleData.mutableBytes;
595					for ( id sample in newData ) {
596						if ( [sample respondsToSelector:@selector(floatValue)] ) {
597							*toBytes++ = (float complex)[(NSNumber *)sample floatValue];
598						}
599						else {
600							*toBytes++ = NAN;
601						}
602					}
603				}
604					break;
605				case sizeof(double complex): {
606					double complex *toBytes = (double complex *)sampleData.mutableBytes;
607					for ( id sample in newData ) {
608						if ( [sample respondsToSelector:@selector(doubleValue)] ) {
609							*toBytes++ = (double complex)[(NSNumber *)sample doubleValue];
610						}
611						else {
612							*toBytes++ = NAN;
613						}
614					}
615				}
616					break;
617			}
618			break;
619		case CPTDecimalDataType:
620			switch ( newDataType.sampleBytes ) {
621				case sizeof(NSDecimal): {
622					NSDecimal *toBytes = (NSDecimal *)sampleData.mutableBytes;
623					for ( id sample in newData ) {
624						if ( [sample respondsToSelector:@selector(decimalValue)] ) {
625							*toBytes++ = (NSDecimal)[(NSNumber *)sample decimalValue];
626						}
627						else {
628							*toBytes++ = CPTDecimalNaN();
629						}
630					}
631				}
632					break;
633			}
634			break;
635	}
636
637	// End of code generated with "CPTNumericData+TypeConversions_Generation.py"
638	// ========================================================================
639
640	if ( (newDataType.byteOrder != CFByteOrderGetCurrent()) && (newDataType.byteOrder != CFByteOrderUnknown) ) {
641		[self swapByteOrderForData:sampleData sampleSize:newDataType.sampleBytes];
642	}
643
644	return [sampleData autorelease];
645}
646
647#pragma mark -
648#pragma mark Description
649
650-(NSString *)description
651{
652	NSUInteger sampleCount = self.numberOfSamples;
653    NSMutableString *descriptionString = [NSMutableString stringWithCapacity:sampleCount * 3];
654    [descriptionString appendFormat:@"<%@ [", [super description]];
655    for ( NSUInteger i = 0; i < sampleCount; i++ ) {
656		if ( i > 0 ) {
657			[descriptionString appendFormat:@","];
658		}
659        [descriptionString appendFormat:@" %@", [self sampleValue:i]];
660    }
661    [descriptionString appendFormat:@" ] {%@, %@}>", CPTDataTypeStringFromDataType(self.dataType), self.shape];
662
663    return descriptionString;
664}
665
666#pragma mark -
667#pragma mark NSMutableCopying
668
669-(id)mutableCopyWithZone:(NSZone *)zone
670{
671    return [[CPTMutableNumericData allocWithZone:zone] initWithData:self.data
672														  dataType:self.dataType
673                                                             shape:self.shape];
674}
675
676#pragma mark -
677#pragma mark NSCopying
678
679-(id)copyWithZone:(NSZone *)zone
680{
681    return [[[self class] allocWithZone:zone] initWithData:self.data
682												  dataType:self.dataType
683                                                     shape:self.shape];
684}
685
686#pragma mark -
687#pragma mark NSCoding
688
689-(void)encodeWithCoder:(NSCoder *)encoder
690{
691    //[super encodeWithCoder:encoder];
692
693    if ( [encoder allowsKeyedCoding] ) {
694        [encoder encodeObject:self.data forKey:@"CPTNumericData.data"];
695
696		CPTNumericDataType selfDataType = self.dataType;
697		[encoder encodeInteger:selfDataType.dataTypeFormat forKey:@"CPTNumericData.dataType.dataTypeFormat"];
698        [encoder encodeInteger:selfDataType.sampleBytes forKey:@"CPTNumericData.dataType.sampleBytes"];
699        [encoder encodeInteger:selfDataType.byteOrder forKey:@"CPTNumericData.dataType.byteOrder"];
700
701        [encoder encodeObject:self.shape forKey:@"CPTNumericData.shape"];
702    }
703	else {
704        [encoder encodeObject:self.data];
705
706		CPTNumericDataType selfDataType = self.dataType;
707		[encoder encodeValueOfObjCType:@encode(CPTDataTypeFormat) at:&(selfDataType.dataTypeFormat)];
708        [encoder encodeValueOfObjCType:@encode(NSUInteger) at:&(selfDataType.sampleBytes)];
709        [encoder encodeValueOfObjCType:@encode(CFByteOrder) at:&(selfDataType.byteOrder)];
710
711        [encoder encodeObject:self.shape];
712    }
713}
714
715-(id)initWithCoder:(NSCoder *)decoder
716{
717	if ( (self = [super init]) ) {
718		NSData *newData;
719		CPTNumericDataType newDataType;
720		NSArray	*shapeArray;
721
722		if ( [decoder allowsKeyedCoding] ) {
723			newData = [decoder decodeObjectForKey:@"CPTNumericData.data"];
724
725			newDataType = CPTDataType([decoder decodeIntegerForKey:@"CPTNumericData.dataType.dataTypeFormat"],
726									 [decoder decodeIntegerForKey:@"CPTNumericData.dataType.sampleBytes"],
727									 [decoder decodeIntegerForKey:@"CPTNumericData.dataType.byteOrder"]);
728
729			shapeArray = [decoder decodeObjectForKey:@"CPTNumericData.shape"];
730		}
731		else {
732			newData = [decoder decodeObject];
733
734			[decoder decodeValueOfObjCType:@encode(CPTDataTypeFormat) at:&(newDataType.dataTypeFormat)];
735			[decoder decodeValueOfObjCType:@encode(NSUInteger) at:&(newDataType.sampleBytes)];
736			[decoder decodeValueOfObjCType:@encode(CFByteOrder) at:&(newDataType.byteOrder)];
737
738			shapeArray = [decoder decodeObject];
739		}
740
741		[self commonInitWithData:newData dataType:newDataType shape:shapeArray];
742	}
743
744    return self;
745}
746
747@end
748