set a bunch of svn:executable properties
[couchdbimport.git] / CouchProjects / Fabric / Element.h
blobbdf7a0b04a6f099cc2f7bbc2ba6e08e4add2eaef
1 /*
2 Fabric formula engine
3 Copyright (C) 2006 Damien Katz
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #ifndef FABRIC_ELEMENT_H
22 #define FABRIC_ELEMENT_H
23 #include "Fabric.h"
24 #include <string.h>
25 #include <time.h>
26 #include "FabricSTL.h"
27 #include <math.h>
29 #ifdef WIN32
30 #define snprintf _snprintf
31 #endif
33 #pragma pack(push, r1, 4)
35 bool InitCollate();
36 bool InitCaseMap();
38 // The order of the elements in the Enum determines their collation sequence.
39 enum ElementType
41 UNKNOWN,
42 NUMBER,
43 TIME,
44 TEXT,
45 RUNTIME_ERROR,
46 KEYWORD,
49 class Element;
50 class TextElement;
51 class NumberElement;
52 class KeywordElement;
53 class ErrorElement;
55 class ElementBase
57 public:
59 virtual const TextElement ToText(MA* ma) const = 0;
60 virtual bool ToBool() const = 0;
61 virtual ElementType GetType() const = 0;
63 virtual const NumberElement ToNumber() const;
64 virtual const ErrorElement ToError() const;
65 virtual const KeywordElement ToKeyword() const;
67 virtual long ToLong() const;
70 const Element ConvertTo(MA* ma, ElementType) const;
74 class TextElement : public ElementBase
76 const unsigned char* m_p;
77 size_t m_len;
79 static unsigned char DefaultNullChar;
81 public:
83 TextElement()
84 : m_p(&DefaultNullChar), m_len(0)
87 TextElement(const char* pStr, size_t len)
88 : m_p((const unsigned char*)pStr), m_len(len)
91 TextElement(const char* pStr)
92 : m_p((const unsigned char*)pStr), m_len(strlen(pStr))
95 virtual bool ToBool() const
97 // non null strings are true
98 return m_len > 0;
101 virtual ElementType GetType() const
103 return TEXT;
106 const char* Ptr() const
108 return (const char*)m_p;
111 size_t Length() const
113 return m_len;
116 const TextElement ToText(MA* ma) const
118 return *this;
121 TextElement Concat(MA* ma, const TextElement& other)
123 char* pNewBuffer = new(ma) char[m_len + other.m_len];
125 // copy in our string
126 memcpy(pNewBuffer, m_p, m_len);
128 // copy in the other string
129 memcpy(pNewBuffer + m_len, other.m_p, other.m_len);
131 return TextElement(pNewBuffer, m_len + other.m_len);
134 virtual const NumberElement ToNumber() const;
136 int Compare(const TextElement& right) const
138 return Compare(*this, right);
141 int CompareI(const TextElement& right) const
143 return CompareI(*this, right);
146 int Equals(const TextElement& right) const
148 return Compare(*this, right) == 0;
151 int EqualsI(const TextElement& right) const
153 return CompareI(*this, right) == 0;
156 static int Compare(const TextElement& left, const TextElement& right);
157 static int CompareI(const TextElement& left, const TextElement& right);
159 int Characters() const;
161 bool operator < (const TextElement& right) const
163 return Compare(*this, right) == 1;
166 char* ToNullTermStr(MA* ma) const
168 char* pReturnValue = new(ma) char[m_len + 1];
169 memcpy(pReturnValue, m_p, m_len);
170 pReturnValue[m_len] = 0;
172 return pReturnValue;
175 TextElement ExtractTrailingNumber(long* pTrailingNumber) const;
177 static TextElement MakeCopy(MA* ma, const char* pString)
179 return MakeCopy(ma, pString, strlen(pString));
182 static TextElement MakeCopy(MA* ma, const char* pString, size_t len)
184 char* p = new(ma) char[len];
185 memcpy(p, pString, len);
187 return TextElement(p, len);
190 static TextElement MakeCopy(MA* ma, const TextElement& text)
192 char* p = new(ma) char[text.m_len];
193 memcpy(p, text.m_p, text.m_len);
195 return TextElement(p, text.m_len);
198 int LenInt() const
200 return (int)m_len;
203 bool Begins(const TextElement& t) const
205 if (t.m_len > m_len) {
206 return false;
208 if (memcmp(t.m_p, m_p, t.m_len) == 0) {
209 return true;
211 return false;
217 #define TEXT_ELEMENT(stringLiteral) TextElement(stringLiteral, sizeof(stringLiteral)-1)
219 class NumberElement : public ElementBase
221 double m_value;
222 public:
223 NumberElement(double number)
224 : m_value(number) {}
225 NumberElement()
226 : m_value(0.0) {}
228 operator double() const
230 return m_value;
233 virtual bool ToBool() const
235 return m_value != 0;
238 virtual ElementType GetType() const
240 return NUMBER;
243 const TextElement ToText(MA* ma) const
245 char buffer[200];
246 snprintf(buffer, sizeof(buffer)-1, "%.f", m_value);
248 return TextElement::MakeCopy(ma, buffer);
251 const NumberElement ToNumber() const
253 return *this;
260 class StringBuilder
262 char* m_pBegin;
263 char* m_pCurrent;
264 size_t m_size;
265 MA* ma;
266 public:
268 StringBuilder(MA* maIn, size_t initialSize)
269 : ma(maIn)
271 m_pBegin = m_pCurrent = new(ma) char[initialSize];
272 *m_pBegin = 0;
273 m_size = initialSize;
276 void Append(const char* str, size_t appendLen)
278 size_t currentLen = m_pCurrent - m_pBegin;
279 size_t spaceLeft = m_size - currentLen;
280 if (appendLen + 1 <= spaceLeft) {
281 memcpy(m_pCurrent, str, appendLen);
282 m_pCurrent += appendLen;
283 *m_pCurrent = 0;
285 else {
286 size_t newSize = (currentLen + appendLen)*2;
287 char* pNew = new(ma) char[newSize];
288 memcpy(pNew, m_pBegin, currentLen);
289 memcpy(pNew + currentLen, str, appendLen);
290 m_size = newSize;
291 m_pBegin = pNew;
292 m_pCurrent = pNew + currentLen + appendLen;
293 *m_pCurrent = 0;
297 StringBuilder& operator += (const char* str)
299 Append(str,strlen(str));
300 return *this;
303 StringBuilder& operator += (const TextElement& t)
305 Append(t.Ptr(), t.Length());
306 return *this;
309 StringBuilder& operator += (int ival)
311 char buffer[200];
312 snprintf(buffer, sizeof(buffer)-1, "%i", ival);
313 Append(buffer, strlen(buffer));
314 return *this;
317 // always null terminated
318 operator const char* ()
320 return m_pBegin;
323 size_t Length() const
325 return m_pCurrent - m_pBegin;
330 class TimeElement : public ElementBase
332 public:
333 double time;
337 class ErrorElement : public ElementBase
339 const char* m_typeId;
340 const char* m_message;
341 public:
342 ErrorElement(RuntimeException& e)
343 : m_typeId(e.typeId()), m_message(e.what())
346 ErrorElement(const char* typeId, const char* message)
347 : m_typeId(typeId), m_message(message)
350 virtual bool ToBool() const
352 return false;
355 virtual ElementType GetType() const
357 return RUNTIME_ERROR;
360 virtual const TextElement ToText(MA* ma) const
362 StringBuilder str(ma,100);
363 str += m_typeId;
364 str += ": ";
365 str += m_message;
366 return TextElement(str, str.Length());
369 const TextElement TypeId() const
371 return TextElement(m_typeId);
374 const ErrorElement ToError() const
376 return *this;
382 class KeywordElement : public ElementBase
384 // store the keyword text as a null terminated string
385 // with its atom. Using the atom makes keyword comparisons
386 // fast and using a null terminated string saves Element
387 // space by not having a length member.
388 const char* m_pKeyword;
389 IdAtom m_keywordID;
391 public:
393 KeywordElement(IdAtom keywordID, const char* pKeyword)
394 : m_keywordID(keywordID), m_pKeyword(pKeyword)
398 bool ToBool() const
400 return true;
403 ElementType GetType() const
405 return KEYWORD;
408 const TextElement ToText(MA* ma) const
410 return TextElement(m_pKeyword, strlen(m_pKeyword));
413 const KeywordElement ToKeyword() const
415 return *this;
418 IdAtom GetIdAtom()
420 return m_keywordID;
424 #define MAXSIZE(A,B) (A > B ? A : B)
426 #define ELEMENT_UNION_SIZE MAXSIZE(MAXSIZE(MAXSIZE(\
427 sizeof(NumberElement), \
428 sizeof(TextElement)), \
429 sizeof(ErrorElement)), \
430 sizeof(KeywordElement))
432 class Element
434 unsigned char m_element[ELEMENT_UNION_SIZE];
436 public:
438 static const Element DefaultElement;
440 Element(const Element& elementIn)
442 memcpy(m_element, elementIn.m_element, sizeof(m_element));
445 Element(const TextElement& text)
447 memcpy(m_element, &text, sizeof(text));
450 Element(const char* pValue, size_t len)
452 TextElement* p = new((void*)m_element) TextElement(pValue, len);
455 Element(const NumberElement& number)
457 memcpy(m_element, &number, sizeof(number));
460 Element(const ErrorElement& element)
462 memcpy(m_element, &element, sizeof(element));
465 Element(const KeywordElement& element)
467 memcpy(m_element, &element, sizeof(element));
470 operator const ElementBase*() const
472 return (const ElementBase*)m_element;
475 const ElementBase* operator->() const
477 return (const ElementBase*)m_element;
480 ElementBase* operator->()
482 return (ElementBase*)m_element;
485 Element(RuntimeException& e)
487 ErrorElement* p = new((void*)m_element) ErrorElement(e);
490 Element(KeywordElement& keyword)
492 memcpy(m_element, &keyword, sizeof(keyword));
496 Element()
498 //This is guard to make sure we don't accidently expand the size of
499 // an element. 12 bytes, The first DWORD is vtable Id for the class,
500 // and each element then has 8 bytes to work with.
501 int size = sizeof(Element);
502 ASSERT(size == 12);
503 TextElement* p = new((void*)m_element) TextElement();
507 int Equals(const Element& other) const
509 return Collate(*this, other) == 0;
512 // are the values equal, case insenstitive for text
513 int EqualsI(const Element& other) const
515 return Collate(*this, other, true) == 0;
518 static int Collate(const Element& a, const Element& b, bool insensitive=false);
520 class ConversionException : public RuntimeException
522 public:
523 ConversionException(const char* message)
524 : RuntimeException("conversion", message)
529 private:
530 Element(int);
531 Element(long);
532 Element(size_t);
535 inline const NumberElement TextElement::ToNumber() const
537 char buffer[200];
538 memcpy(buffer, m_p, std::min(m_len, sizeof(buffer)-1));
539 buffer[std::min(m_len, sizeof(buffer)-1)] = 0; // null terminate
540 return NumberElement(atof(buffer));
544 inline
545 long ElementBase::ToLong() const
547 double d = ToNumber();
548 return (long)d;
551 inline
552 const KeywordElement ElementBase::ToKeyword() const
554 throw Element::ConversionException("Cannot convert value to a keyword");
557 inline
558 const ErrorElement ElementBase::ToError() const
560 throw Element::ConversionException("Cannot convert value to a error");
563 inline
564 const NumberElement ElementBase::ToNumber() const
566 throw Element::ConversionException("Cannot convert value to a number");
569 inline
570 const Element ElementBase::ConvertTo(MA* ma, ElementType type) const
572 switch (type) {
573 case TEXT:
574 return ToText(ma);
575 case NUMBER:
576 return ToNumber();
577 case RUNTIME_ERROR:
578 return ToError();
579 case KEYWORD:
580 return ToKeyword();
581 default:
582 throw Element::ConversionException("Cannot convert value.");
586 inline
587 int Element::Collate(const Element& aIn, const Element& bIn, bool bInsensitive)
589 const ElementBase& a = *(ElementBase*)aIn.m_element;
590 const ElementBase& b = *(ElementBase*)bIn.m_element;
592 ElementType aType = a.GetType();
593 ElementType bType = b.GetType();
595 if (aType < bType) {
596 return -1;
597 } else if (aType > bType) {
598 return 1;
601 switch (aType) {
602 case NUMBER:
604 double dbl_a = ((NumberElement&)a);
605 double dbl_b = ((NumberElement&)b);
606 return cmp(dbl_a, dbl_b);
608 case TEXT:
609 if (bInsensitive) {
610 return TextElement::CompareI((TextElement&)a, (TextElement&)b);
612 else {
613 return TextElement::Compare((TextElement&)a, (TextElement&)b);
615 case TIME:
616 return cmp(((TimeElement&)a).time, ((TimeElement&)b).time);
617 case RUNTIME_ERROR:
618 return TextElement::CompareI(((ErrorElement&)a).TypeId(), ((ErrorElement&)b).TypeId());
619 case KEYWORD:
620 return cmp(((KeywordElement&)a).GetIdAtom(), ((KeywordElement&)b).GetIdAtom());
621 default:
622 return 0;
627 #pragma pack(pop, r1)
629 #endif // FABRIC_ELEMENT_H