aboutsummaryrefslogtreecommitdiffstats
path: root/libparc/parc/algol
diff options
context:
space:
mode:
authorMauro Sardara <msardara+fdio@cisco.com>2018-12-18 11:05:49 +0000
committerGerrit Code Review <gerrit@fd.io>2018-12-18 11:05:49 +0000
commitcada1143501a48effc483e3873596c22849926b5 (patch)
tree93a1da95d69b69328a1e7d3621447797f65137c9 /libparc/parc/algol
parent726949d76a7207694d5a1eee84ef134a8e539115 (diff)
parenta45edf23c2463ac9a4723a24792a6c5c89b1e021 (diff)
Merge "Adding gitreview config file for this branch sub project"
Diffstat (limited to 'libparc/parc/algol')
-rw-r--r--libparc/parc/algol/.gitignore4
-rw-r--r--libparc/parc/algol/Groups.dox41
-rwxr-xr-xlibparc/parc/algol/internal_parc_Event.c324
-rwxr-xr-xlibparc/parc/algol/internal_parc_Event.h168
-rw-r--r--libparc/parc/algol/parc_ArrayList.c381
-rw-r--r--libparc/parc/algol/parc_ArrayList.h577
-rwxr-xr-xlibparc/parc/algol/parc_AtomicInteger.c94
-rwxr-xr-xlibparc/parc/algol/parc_AtomicInteger.h73
-rwxr-xr-xlibparc/parc/algol/parc_Base64.c290
-rw-r--r--libparc/parc/algol/parc_Base64.h129
-rwxr-xr-xlibparc/parc/algol/parc_BitVector.c409
-rwxr-xr-xlibparc/parc/algol/parc_BitVector.h426
-rwxr-xr-xlibparc/parc/algol/parc_Buffer.c1072
-rw-r--r--libparc/parc/algol/parc_Buffer.h1665
-rw-r--r--libparc/parc/algol/parc_BufferChunker.c261
-rwxr-xr-xlibparc/parc/algol/parc_BufferChunker.h217
-rwxr-xr-xlibparc/parc/algol/parc_BufferComposer.c289
-rwxr-xr-xlibparc/parc/algol/parc_BufferComposer.h571
-rwxr-xr-xlibparc/parc/algol/parc_BufferDictionary.c146
-rwxr-xr-xlibparc/parc/algol/parc_BufferDictionary.h145
-rw-r--r--libparc/parc/algol/parc_ByteArray.c312
-rw-r--r--libparc/parc/algol/parc_ByteArray.h580
-rw-r--r--libparc/parc/algol/parc_CMacro.h49
-rwxr-xr-xlibparc/parc/algol/parc_Chunker.c75
-rwxr-xr-xlibparc/parc/algol/parc_Chunker.h250
-rwxr-xr-xlibparc/parc/algol/parc_Clock.c245
-rwxr-xr-xlibparc/parc/algol/parc_Clock.h354
-rwxr-xr-xlibparc/parc/algol/parc_Collection.h32
-rw-r--r--libparc/parc/algol/parc_Deque.c446
-rwxr-xr-xlibparc/parc/algol/parc_Deque.h465
-rwxr-xr-xlibparc/parc/algol/parc_Dictionary.c134
-rwxr-xr-xlibparc/parc/algol/parc_Dictionary.h294
-rwxr-xr-xlibparc/parc/algol/parc_DisplayIndented.c114
-rw-r--r--libparc/parc/algol/parc_DisplayIndented.h62
-rwxr-xr-xlibparc/parc/algol/parc_ElasticString.h439
-rw-r--r--libparc/parc/algol/parc_Environment.c45
-rwxr-xr-xlibparc/parc/algol/parc_Environment.h42
-rwxr-xr-xlibparc/parc/algol/parc_Event.c149
-rw-r--r--libparc/parc/algol/parc_Event.h211
-rw-r--r--libparc/parc/algol/parc_EventBuffer.c282
-rwxr-xr-xlibparc/parc/algol/parc_EventBuffer.h387
-rwxr-xr-xlibparc/parc/algol/parc_EventQueue.c353
-rw-r--r--libparc/parc/algol/parc_EventQueue.h515
-rwxr-xr-xlibparc/parc/algol/parc_EventScheduler.c171
-rw-r--r--libparc/parc/algol/parc_EventScheduler.h224
-rwxr-xr-xlibparc/parc/algol/parc_EventSignal.c127
-rwxr-xr-xlibparc/parc/algol/parc_EventSignal.h136
-rwxr-xr-xlibparc/parc/algol/parc_EventSocket.c140
-rwxr-xr-xlibparc/parc/algol/parc_EventSocket.h116
-rwxr-xr-xlibparc/parc/algol/parc_EventTimer.c128
-rwxr-xr-xlibparc/parc/algol/parc_EventTimer.h138
-rw-r--r--libparc/parc/algol/parc_Execution.c97
-rw-r--r--libparc/parc/algol/parc_Execution.h41
-rw-r--r--libparc/parc/algol/parc_File.c262
-rwxr-xr-xlibparc/parc/algol/parc_File.h278
-rw-r--r--libparc/parc/algol/parc_FileChunker.c282
-rwxr-xr-xlibparc/parc/algol/parc_FileChunker.h219
-rwxr-xr-xlibparc/parc/algol/parc_FileInputStream.c115
-rwxr-xr-xlibparc/parc/algol/parc_FileInputStream.h170
-rwxr-xr-xlibparc/parc/algol/parc_FileOutputStream.c85
-rw-r--r--libparc/parc/algol/parc_FileOutputStream.h142
-rwxr-xr-xlibparc/parc/algol/parc_Hash.c144
-rwxr-xr-xlibparc/parc/algol/parc_Hash.h341
-rwxr-xr-xlibparc/parc/algol/parc_HashCode.c49
-rwxr-xr-xlibparc/parc/algol/parc_HashCode.h94
-rwxr-xr-xlibparc/parc/algol/parc_HashCodeTable.c338
-rw-r--r--libparc/parc/algol/parc_HashCodeTable.h168
-rw-r--r--libparc/parc/algol/parc_HashMap.c666
-rwxr-xr-xlibparc/parc/algol/parc_HashMap.h622
-rwxr-xr-xlibparc/parc/algol/parc_InputStream.c57
-rwxr-xr-xlibparc/parc/algol/parc_InputStream.h117
-rwxr-xr-xlibparc/parc/algol/parc_Iterator.c159
-rw-r--r--libparc/parc/algol/parc_Iterator.h250
-rwxr-xr-xlibparc/parc/algol/parc_JSON.c404
-rwxr-xr-xlibparc/parc/algol/parc_JSON.h658
-rwxr-xr-xlibparc/parc/algol/parc_JSONArray.c185
-rwxr-xr-xlibparc/parc/algol/parc_JSONArray.h333
-rwxr-xr-xlibparc/parc/algol/parc_JSONPair.c267
-rwxr-xr-xlibparc/parc/algol/parc_JSONPair.h486
-rwxr-xr-xlibparc/parc/algol/parc_JSONParser.c181
-rwxr-xr-xlibparc/parc/algol/parc_JSONParser.h309
-rwxr-xr-xlibparc/parc/algol/parc_JSONValue.c1018
-rwxr-xr-xlibparc/parc/algol/parc_JSONValue.h938
-rwxr-xr-xlibparc/parc/algol/parc_KeyValue.c158
-rwxr-xr-xlibparc/parc/algol/parc_KeyValue.h273
-rwxr-xr-xlibparc/parc/algol/parc_KeyedElement.c78
-rwxr-xr-xlibparc/parc/algol/parc_KeyedElement.h128
-rw-r--r--libparc/parc/algol/parc_LinkedList.c705
-rw-r--r--libparc/parc/algol/parc_LinkedList.h698
-rw-r--r--libparc/parc/algol/parc_List.c277
-rw-r--r--libparc/parc/algol/parc_List.h768
-rwxr-xr-xlibparc/parc/algol/parc_Map.c20
-rwxr-xr-xlibparc/parc/algol/parc_Map.h454
-rwxr-xr-xlibparc/parc/algol/parc_Memory.c144
-rw-r--r--libparc/parc/algol/parc_Memory.h468
-rw-r--r--libparc/parc/algol/parc_Network.c390
-rw-r--r--libparc/parc/algol/parc_Network.h299
-rw-r--r--libparc/parc/algol/parc_Object.c952
-rw-r--r--libparc/parc/algol/parc_Object.h1504
-rwxr-xr-xlibparc/parc/algol/parc_OldSortedList.c101
-rwxr-xr-xlibparc/parc/algol/parc_OldSortedList.h122
-rwxr-xr-xlibparc/parc/algol/parc_OutputStream.c81
-rwxr-xr-xlibparc/parc/algol/parc_OutputStream.h190
-rwxr-xr-xlibparc/parc/algol/parc_PathName.c277
-rw-r--r--libparc/parc/algol/parc_PathName.h392
-rwxr-xr-xlibparc/parc/algol/parc_PriorityQueue.c387
-rwxr-xr-xlibparc/parc/algol/parc_PriorityQueue.h223
-rw-r--r--libparc/parc/algol/parc_Properties.c342
-rw-r--r--libparc/parc/algol/parc_Properties.h502
-rwxr-xr-xlibparc/parc/algol/parc_RandomAccessFile.c185
-rwxr-xr-xlibparc/parc/algol/parc_RandomAccessFile.h426
-rwxr-xr-xlibparc/parc/algol/parc_ReadOnlyBuffer.c245
-rw-r--r--libparc/parc/algol/parc_ReadOnlyBuffer.h834
-rw-r--r--libparc/parc/algol/parc_SafeMemory.c658
-rw-r--r--libparc/parc/algol/parc_SafeMemory.h335
-rw-r--r--libparc/parc/algol/parc_SortedList.c252
-rw-r--r--libparc/parc/algol/parc_SortedList.h595
-rwxr-xr-xlibparc/parc/algol/parc_Stack.c76
-rwxr-xr-xlibparc/parc/algol/parc_Stack.h140
-rw-r--r--libparc/parc/algol/parc_StandardOutputStream.c76
-rw-r--r--libparc/parc/algol/parc_StandardOutputStream.h38
-rwxr-xr-xlibparc/parc/algol/parc_StdlibMemory.c180
-rwxr-xr-xlibparc/parc/algol/parc_StdlibMemory.h200
-rwxr-xr-xlibparc/parc/algol/parc_String.c187
-rw-r--r--libparc/parc/algol/parc_String.h391
-rwxr-xr-xlibparc/parc/algol/parc_Time.c154
-rw-r--r--libparc/parc/algol/parc_Time.h262
-rwxr-xr-xlibparc/parc/algol/parc_TreeMap.c1120
-rwxr-xr-xlibparc/parc/algol/parc_TreeMap.h714
-rwxr-xr-xlibparc/parc/algol/parc_TreeRedBlack.c781
-rwxr-xr-xlibparc/parc/algol/parc_TreeRedBlack.h384
-rw-r--r--libparc/parc/algol/parc_URI.c468
-rw-r--r--libparc/parc/algol/parc_URI.h412
-rw-r--r--libparc/parc/algol/parc_URIAuthority.c133
-rw-r--r--libparc/parc/algol/parc_URIAuthority.h237
-rwxr-xr-xlibparc/parc/algol/parc_URIPath.c309
-rwxr-xr-xlibparc/parc/algol/parc_URIPath.h494
-rwxr-xr-xlibparc/parc/algol/parc_URISegment.c276
-rw-r--r--libparc/parc/algol/parc_URISegment.h355
-rw-r--r--libparc/parc/algol/parc_Unsigned.c176
-rwxr-xr-xlibparc/parc/algol/parc_Unsigned.h91
-rwxr-xr-xlibparc/parc/algol/parc_Varint.c543
-rwxr-xr-xlibparc/parc/algol/parc_Varint.h478
-rwxr-xr-xlibparc/parc/algol/parc_Vector.c81
-rwxr-xr-xlibparc/parc/algol/parc_Vector.h109
-rw-r--r--libparc/parc/algol/test/.gitignore73
-rw-r--r--libparc/parc/algol/test/CMakeLists.txt76
-rw-r--r--libparc/parc/algol/test/_test_parc_URI.h57
-rw-r--r--libparc/parc/algol/test/data.json2614
-rwxr-xr-xlibparc/parc/algol/test/test_parc_ArrayList.c658
-rw-r--r--libparc/parc/algol/test/test_parc_AtomicInteger.c156
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Base64.c414
-rwxr-xr-xlibparc/parc/algol/test/test_parc_BitVector.c438
-rw-r--r--libparc/parc/algol/test/test_parc_Buffer.c1502
-rwxr-xr-xlibparc/parc/algol/test/test_parc_BufferChunker.c336
-rw-r--r--libparc/parc/algol/test/test_parc_BufferComposer.c448
-rwxr-xr-xlibparc/parc/algol/test/test_parc_ByteArray.c499
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Chunker.c271
-rw-r--r--libparc/parc/algol/test/test_parc_Clock.c198
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Deque.c620
-rw-r--r--libparc/parc/algol/test/test_parc_Dictionary.c736
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Display.c85
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Environment.c86
-rw-r--r--libparc/parc/algol/test/test_parc_Event.c243
-rw-r--r--libparc/parc/algol/test/test_parc_EventBuffer.c345
-rw-r--r--libparc/parc/algol/test/test_parc_EventQueue.c402
-rwxr-xr-xlibparc/parc/algol/test/test_parc_EventScheduler.c263
-rw-r--r--libparc/parc/algol/test/test_parc_EventSignal.c167
-rw-r--r--libparc/parc/algol/test/test_parc_EventSocket.c128
-rwxr-xr-xlibparc/parc/algol/test/test_parc_EventTimer.c143
-rw-r--r--libparc/parc/algol/test/test_parc_File.c208
-rwxr-xr-xlibparc/parc/algol/test/test_parc_FileChunker.c431
-rwxr-xr-xlibparc/parc/algol/test/test_parc_FileInputStream.c107
-rwxr-xr-xlibparc/parc/algol/test/test_parc_FileOutputStream.c167
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Hash.c253
-rwxr-xr-xlibparc/parc/algol/test/test_parc_HashCode.c109
-rwxr-xr-xlibparc/parc/algol/test/test_parc_HashCodeTable.c423
-rw-r--r--libparc/parc/algol/test/test_parc_HashMap.c915
-rwxr-xr-xlibparc/parc/algol/test/test_parc_InputStream.c109
-rw-r--r--libparc/parc/algol/test/test_parc_Iterator.c192
-rw-r--r--libparc/parc/algol/test/test_parc_JSON.c690
-rwxr-xr-xlibparc/parc/algol/test/test_parc_JSONArray.c227
-rw-r--r--libparc/parc/algol/test/test_parc_JSONPair.c421
-rwxr-xr-xlibparc/parc/algol/test/test_parc_JSONParser.c310
-rw-r--r--libparc/parc/algol/test/test_parc_JSONValue.c1365
-rwxr-xr-xlibparc/parc/algol/test/test_parc_KeyValue.c386
-rwxr-xr-xlibparc/parc/algol/test/test_parc_KeyedElement.c134
-rw-r--r--libparc/parc/algol/test/test_parc_LinkedList.c1192
-rw-r--r--libparc/parc/algol/test/test_parc_List.c872
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Memory.c220
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Network.c668
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Object.c1580
-rwxr-xr-xlibparc/parc/algol/test/test_parc_PathName.c458
-rw-r--r--libparc/parc/algol/test/test_parc_PriorityQueue.c492
-rw-r--r--libparc/parc/algol/test/test_parc_Properties.c277
-rw-r--r--libparc/parc/algol/test/test_parc_RandomAccessFile.c380
-rw-r--r--libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c689
-rw-r--r--libparc/parc/algol/test/test_parc_SafeMemory.c813
-rw-r--r--libparc/parc/algol/test/test_parc_SortedList.c510
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Stack.c119
-rw-r--r--libparc/parc/algol/test/test_parc_StdlibMemory.c326
-rw-r--r--libparc/parc/algol/test/test_parc_String.c210
-rw-r--r--libparc/parc/algol/test/test_parc_Time.c144
-rwxr-xr-xlibparc/parc/algol/test/test_parc_TreeMap.c1565
-rwxr-xr-xlibparc/parc/algol/test/test_parc_TreeRedBlack.c1461
-rw-r--r--libparc/parc/algol/test/test_parc_URI.c642
-rw-r--r--libparc/parc/algol/test/test_parc_URIAuthority.c267
-rw-r--r--libparc/parc/algol/test/test_parc_URIPath.c406
-rw-r--r--libparc/parc/algol/test/test_parc_URISegment.c315
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Varint.c310
-rw-r--r--libparc/parc/algol/test/test_parc_Vector.c116
211 files changed, 77537 insertions, 0 deletions
diff --git a/libparc/parc/algol/.gitignore b/libparc/parc/algol/.gitignore
new file mode 100644
index 00000000..cf23441d
--- /dev/null
+++ b/libparc/parc/algol/.gitignore
@@ -0,0 +1,4 @@
+parcAlgol_About.c
+parcLibrary_About.c
+parcLibrary_About.h
+parcLibrary
diff --git a/libparc/parc/algol/Groups.dox b/libparc/parc/algol/Groups.dox
new file mode 100644
index 00000000..f798378c
--- /dev/null
+++ b/libparc/parc/algol/Groups.dox
@@ -0,0 +1,41 @@
+/**
+\mainpage
+The PARC Library is a collection of data structures, algorithms,
+abstractions and generally useful facilities for C programs.
+
+The most notable facility of the PARC library is the use of `PARCObject`
+reference counted allocated memory.
+
+The general abstractions provided by the library try to follow along with the
+Java runtime.
+For example, the PARC Library provides `PARCHashMap`, `PARCLinkedList`,
+`PARCInputStream`, and so forth.
+Ideally, the Java programmer will feel at home with the PARC Library.
+
+@defgroup types Basic Types
+@brief Basic Types
+
+@defgroup object Reference counted object types
+@brief Reference counted object types
+
+@defgroup datastructures Data Structures
+@brief Data structures
+
+@defgroup inputoutput Input Output
+@brief Functions to manage input and output.
+
+@defgroup memory Memory and Buffer Management
+@brief Functions to manage memory and references to memory.
+
+@defgroup threading Threading and Concurrency
+@brief Functions to manage Threading and Concurrency.
+
+@defgroup security Security
+@brief Functions to manage Security.
+
+@defgroup developer Developer Aids
+@brief Functions to provide Developer Aids.
+
+@defgroup networking Networking and Communication
+@brief Functions to manage Networking and Communication.
+*/
diff --git a/libparc/parc/algol/internal_parc_Event.c b/libparc/parc/algol/internal_parc_Event.c
new file mode 100755
index 00000000..74e917bf
--- /dev/null
+++ b/libparc/parc/algol/internal_parc_Event.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include "internal_parc_Event.h"
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+#include <event2/bufferevent.h>
+
+void *
+internal_parc_alloc(size_t size)
+{
+ void *pointer;
+
+ pointer = parcMemory_AllocateAndClear(size);
+ return pointer;
+}
+
+void *
+internal_parc_realloc(void *pointer, size_t newSize)
+{
+ void *newPointer;
+ newPointer = parcMemory_Reallocate(pointer, newSize);
+ return newPointer;
+}
+
+// We interpose on the standard "free" interface to protect against freed memory accesses.
+void
+internal_parc_free(void *ptr)
+{
+ parcMemory_Deallocate((void **) &ptr);
+}
+
+static int _libeventInitialized = 0;
+
+void
+internal_parc_initializeLibevent(void)
+{
+ if (_libeventInitialized) {
+ return;
+ }
+ _libeventInitialized = 1;
+
+ // 0x AA BB CC XX
+ // AA = major
+ // BB = minor
+ // CC = patchlevel
+ //
+ uint32_t version = event_get_version_number();
+ trapIllegalValueIf(version < 0x02001000UL,
+ "Libevent version must be at least 2.0.16, got %s",
+ event_get_version());
+
+ // Make sure libevent uses our memory allocator.
+ // Libevent allocates an internal object the first time a base is allocated
+ // that it never releases. In order to ensure our outstanding memory counters
+ // start at zero we trigger this allocation before interposing our memory allocator.
+ //
+ // Create a scheduler event base, an event, then free both of them.
+ //
+ struct event_base *evbase = event_base_new();
+ assertNotNull(evbase, "Libevent event_base_new returned NULL");
+ struct event *event = event_new(evbase, -1, 0, NULL, NULL);
+ assertNotNull(event, "Libevent event_new returned NULL");
+ event_del(event);
+ event_base_free(evbase);
+ event_free(event);
+
+ event_set_mem_functions(internal_parc_alloc,
+ internal_parc_realloc,
+ internal_parc_free);
+}
+
+PARCEventPriority
+internal_libevent_priority_to_PARCEventPriority(short evpriority)
+{
+ PARCEventPriority priority = 0;
+ switch (evpriority) {
+ case 0: priority = PARCEventPriority_Maximum;
+ break;
+ case 1: priority = PARCEventPriority_Normal;
+ break;
+ case 2: priority = PARCEventPriority_Minimum;
+ break;
+ default:
+ assertTrue(0, "Unknown Libevent priority 0x%x\n", evpriority);
+ break;
+ }
+ return priority;
+}
+
+short
+internal_PARCEventPriority_to_libevent_priority(PARCEventPriority priority)
+{
+ short evpriority = 0;
+ switch (priority) {
+ case PARCEventPriority_Maximum: evpriority = 0;
+ break;
+ case PARCEventPriority_Normal: evpriority = 1;
+ break;
+ case PARCEventPriority_Minimum: evpriority = 2;
+ break;
+ default:
+ assertTrue(0, "Unknown PARCEventPriority 0x%x\n", evpriority);
+ break;
+ }
+ return evpriority;
+}
+
+PARCEventSchedulerDispatchType
+internal_eventloop_options_to_PARCEventSchedulerDispatchType(short evoptions)
+{
+ PARCEventSchedulerDispatchType options = 0;
+ switch (evoptions) {
+ case 0: options = PARCEventSchedulerDispatchType_Blocking;
+ break;
+ case EVLOOP_ONCE: options = PARCEventSchedulerDispatchType_LoopOnce;
+ break;
+ case EVLOOP_NONBLOCK: options = PARCEventSchedulerDispatchType_NonBlocking;
+ break;
+ default:
+ assertTrue(0, "Unknown Libevent dispatcher flag 0x%x\n", evoptions);
+ break;
+ }
+ return options;
+}
+
+short
+internal_PARCEventSchedulerDispatchType_to_eventloop_options(PARCEventSchedulerDispatchType options)
+{
+ short evoptions = 0;
+ switch (options) {
+ case PARCEventSchedulerDispatchType_Blocking: evoptions = 0;
+ break;
+ case PARCEventSchedulerDispatchType_LoopOnce: evoptions = EVLOOP_ONCE;
+ break;
+ case PARCEventSchedulerDispatchType_NonBlocking: evoptions = EVLOOP_NONBLOCK;
+ break;
+ default:
+ assertTrue(0, "Unknown PARCEventSchedulerDispatchType option 0x%x\n", evoptions);
+ break;
+ }
+ return evoptions;
+}
+
+PARCEventQueueOption
+internal_bufferevent_options_to_PARCEventQueueOption(short evflags)
+{
+ PARCEventQueueOption flags = 0;
+ if (evflags & BEV_OPT_CLOSE_ON_FREE) {
+ flags |= PARCEventQueueOption_CloseOnFree;
+ evflags &= ~BEV_OPT_CLOSE_ON_FREE;
+ }
+ if (evflags & BEV_OPT_DEFER_CALLBACKS) {
+ flags |= PARCEventQueueOption_DeferCallbacks;
+ evflags &= ~BEV_OPT_DEFER_CALLBACKS;
+ }
+ assertTrue(evflags == 0, "Unknown Libevent option flag 0x%x\n", evflags);
+ return flags;
+}
+
+short
+internal_PARCEventQueueOption_to_bufferevent_options(PARCEventQueueOption flags)
+{
+ short evflags = 0;
+ if (flags & PARCEventQueueOption_CloseOnFree) {
+ evflags |= BEV_OPT_CLOSE_ON_FREE;
+ flags &= ~PARCEventQueueOption_CloseOnFree;
+ }
+ if (flags & PARCEventQueueOption_DeferCallbacks) {
+ evflags |= BEV_OPT_DEFER_CALLBACKS;
+ flags &= ~PARCEventQueueOption_DeferCallbacks;
+ }
+ assertTrue(flags == 0, "Unknown PARCEventQueueOption flag 0x%x\n", flags);
+ return evflags;
+}
+
+PARCEventQueueEventType
+internal_bufferevent_type_to_PARCEventQueueEventType(short evtypes)
+{
+ PARCEventQueueEventType types = 0;
+ if (evtypes & BEV_EVENT_READING) {
+ types |= PARCEventQueueEventType_Reading;
+ evtypes &= ~BEV_EVENT_READING;
+ }
+ if (evtypes & BEV_EVENT_WRITING) {
+ types |= PARCEventQueueEventType_Writing;
+ evtypes &= ~BEV_EVENT_WRITING;
+ }
+ if (evtypes & BEV_EVENT_EOF) {
+ types |= PARCEventQueueEventType_EOF;
+ evtypes &= ~BEV_EVENT_EOF;
+ }
+ if (evtypes & BEV_EVENT_ERROR) {
+ types |= PARCEventQueueEventType_Error;
+ evtypes &= ~BEV_EVENT_ERROR;
+ }
+ if (evtypes & BEV_EVENT_TIMEOUT) {
+ types |= PARCEventQueueEventType_Timeout;
+ evtypes &= ~BEV_EVENT_TIMEOUT;
+ }
+ if (evtypes & BEV_EVENT_CONNECTED) {
+ types |= PARCEventQueueEventType_Connected;
+ evtypes &= ~BEV_EVENT_CONNECTED;
+ }
+ assertTrue(evtypes == 0, "Unknown Libevent type flag 0x%x\n", evtypes);
+ return types;
+}
+
+short
+internal_PARCEventQueueEventType_to_bufferevent_type(PARCEventQueueEventType types)
+{
+ short evtypes = 0;
+ if (types & PARCEventQueueEventType_Reading) {
+ evtypes |= BEV_EVENT_READING;
+ types &= ~PARCEventQueueEventType_Reading;
+ }
+ if (types & PARCEventQueueEventType_Writing) {
+ evtypes |= BEV_EVENT_WRITING;
+ types &= ~PARCEventQueueEventType_Writing;
+ }
+ if (types & PARCEventQueueEventType_EOF) {
+ evtypes |= BEV_EVENT_EOF;
+ types &= ~PARCEventQueueEventType_EOF;
+ }
+ if (types & PARCEventQueueEventType_Error) {
+ evtypes |= BEV_EVENT_ERROR;
+ types &= ~PARCEventQueueEventType_Error;
+ }
+ if (types & PARCEventQueueEventType_Timeout) {
+ evtypes |= BEV_EVENT_TIMEOUT;
+ types &= ~PARCEventQueueEventType_Timeout;
+ }
+ if (types & PARCEventQueueEventType_Connected) {
+ evtypes |= BEV_EVENT_CONNECTED;
+ types &= ~PARCEventQueueEventType_Connected;
+ }
+ assertTrue(types == 0, "Unknown PARCEventQueueEventType 0x%x\n", types);
+ return evtypes;
+}
+
+PARCEventType
+internal_libevent_type_to_PARCEventType(short evtypes)
+{
+ PARCEventType types = 0;
+ if (evtypes & EV_TIMEOUT) {
+ types |= PARCEventType_Timeout;
+ evtypes &= ~EV_TIMEOUT;
+ }
+ if (evtypes & EV_READ) {
+ types |= PARCEventType_Read;
+ evtypes &= ~EV_READ;
+ }
+ if (evtypes & EV_WRITE) {
+ types |= PARCEventType_Write;
+ evtypes &= ~EV_WRITE;
+ }
+ if (evtypes & EV_SIGNAL) {
+ types |= PARCEventType_Signal;
+ evtypes &= ~EV_SIGNAL;
+ }
+ if (evtypes & EV_PERSIST) {
+ types |= PARCEventType_Persist;
+ evtypes &= ~EV_PERSIST;
+ }
+ if (evtypes & EV_ET) {
+ types |= PARCEventType_EdgeTriggered;
+ evtypes &= ~EV_ET;
+ }
+ assertTrue(evtypes == 0, "Unknown Libevent event type 0x%x\n", evtypes);
+ return types;
+}
+
+short
+internal_PARCEventType_to_libevent_type(PARCEventType types)
+{
+ short evtypes = 0;
+ if (types & PARCEventType_Timeout) {
+ evtypes |= EV_TIMEOUT;
+ types &= ~PARCEventType_Timeout;
+ }
+ if (types & PARCEventType_Read) {
+ evtypes |= EV_READ;
+ types &= ~PARCEventType_Read;
+ }
+ if (types & PARCEventType_Write) {
+ evtypes |= EV_WRITE;
+ types &= ~PARCEventType_Write;
+ }
+ if (types & PARCEventType_Signal) {
+ evtypes |= EV_SIGNAL;
+ types &= ~PARCEventType_Signal;
+ }
+ if (types & PARCEventType_Persist) {
+ evtypes |= EV_PERSIST;
+ types &= ~PARCEventType_Persist;
+ }
+ if (types & PARCEventType_EdgeTriggered) {
+ evtypes |= EV_ET;
+ types &= ~PARCEventType_EdgeTriggered;
+ }
+ assertTrue(types == 0, "Unknown Libevent event type 0x%x\n", types);
+ return evtypes;
+}
diff --git a/libparc/parc/algol/internal_parc_Event.h b/libparc/parc/algol/internal_parc_Event.h
new file mode 100755
index 00000000..ab157a56
--- /dev/null
+++ b/libparc/parc/algol/internal_parc_Event.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventQueue.h
+ * @ingroup events
+ * @brief Queue buffer events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_internal_parc_Event_h
+#define libparc_internal_parc_Event_h
+
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventQueue.h>
+
+/**
+ * Map alloc() method call to a PARC internal memory method
+ *
+ * @param [in] size of memory to allocate
+ * @returns NULL on error, memory pointer on success.
+ *
+ * Example:
+ * @code
+ * {
+ * return internal_parc_alloc(1024);
+ * }
+ * @endcode
+ *
+ */
+void *internal_parc_alloc(size_t size);
+
+/**
+ * Map realloc() method call to a PARC internal memory method
+ *
+ * @param [in] pointer to memory to reallocate
+ * @param [in] newSize of memory to allocate
+ * @returns NULL on error, new memory pointer on success.
+ *
+ * Example:
+ * @code
+ * {
+ * return internal_parc_realloc(ptr, 2048);
+ * }
+ * @endcode
+ *
+ */
+void *internal_parc_realloc(void *pointer, size_t newSize);
+
+/**
+ * Map free() method call to a PARC internal memory method
+ *
+ * @param [in] pointer to memory to free
+ *
+ * Example:
+ * @code
+ * {
+ * internal_parc_free(ptr);
+ * }
+ * @endcode
+ *
+ */
+void internal_parc_free(void *ptr);
+
+/**
+ * Verify and initialize libevent
+ *
+ * Example:
+ * @code
+ * {
+ * internal_parc_initializeLibevent();
+ * }
+ * @endcode
+ *
+ */
+void internal_parc_initializeLibevent(void);
+
+/**
+ * Convert from/to libevent dispatcher options and PARCEventSchedulerDispatcherType options.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventSchedulerDispatchType type = internal_eventloop_options_to_PARCEventSchedulerDispatchType(EVLOOP_ONCE);
+ * short evtype = internal_PARCEventSchedulerDispatchType_to_eventloop_options(PARCEventSchedulerDispatchType_LoopOnce);
+ * }
+ * @endcode
+ *
+ */
+PARCEventSchedulerDispatchType internal_eventloop_options_to_PARCEventSchedulerDispatchType(short evoptions);
+short internal_PARCEventSchedulerDispatchType_to_eventloop_options(PARCEventSchedulerDispatchType options);
+
+/**
+ * Convert from/to libevent bufferevent options and PARCEventQueueOption.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueueOption parcEventQueueOption = internal_bufferevent_options_to_PARCEventQueueOption(BEV_OPT_CLOSE_ON_FREE);
+ * short buffereventOption = internal_PARCEventQueueOption_to_bufferevent_options(PARCEventQueueOption_CloseOnFree);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueueOption internal_bufferevent_options_to_PARCEventQueueOption(short evflags);
+short internal_PARCEventQueueOption_to_bufferevent_options(PARCEventQueueOption flags);
+
+/**
+ * Convert from/to libevent bufferevent types and PARCEventQueueEventType.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueueEventType parcEventQueueEventType = internal_bufferevent_type_to_PARCEventQueueEventType(BEV_EVENT_READING);
+ * short buffereventOptions = internal_PARCEventQueueEventType_to_bufferevent_type(PARCEventQueueEventType_Reading);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueueEventType internal_bufferevent_type_to_PARCEventQueueEventType(short evtypes);
+short internal_PARCEventQueueEventType_to_bufferevent_type(PARCEventQueueEventType types);
+
+/**
+ * Convert from/to libevent event types and PARCEventType.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventType parcEventType = internal_libevent_type_to_PARCEventType(EV_READ);
+ * short buffereventOptions = internal_PARCEventType_to_libevent_type(PARCEventType_Read);
+ * }
+ * @endcode
+ *
+ */
+PARCEventType internal_libevent_type_to_PARCEventType(short evtypes);
+short internal_PARCEventType_to_libevent_type(PARCEventType types);
+
+/**
+ * Convert from/to libevent priority types and PARCEventPriority.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventPriority parcEventPriority = internal_libevent_priority_to_PARCEventPriority(0);
+ * short priority = internal_PARCEventPriority_to_libevent_priority(PARCEventPriority_Normal);
+ * }
+ * @endcode
+ *
+ */
+short internal_PARCEventPriority_to_libevent_priority(PARCEventPriority priority);
+PARCEventPriority internal_libevent_priority_to_PARCEventPriority(short evpriority);
+#endif // libparc_internal_parc_Event_h
diff --git a/libparc/parc/algol/parc_ArrayList.c b/libparc/parc/algol/parc_ArrayList.c
new file mode 100644
index 00000000..e9597070
--- /dev/null
+++ b/libparc/parc/algol/parc_ArrayList.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+PARCListInterface *PARCArrayListAsPARCList = &(PARCListInterface) {
+ .Add = (bool (*)(void *, void *))parcArrayList_Add,
+ .AddAtIndex = (void (*)(void *, int index, void *))parcArrayList_InsertAtIndex,
+ .AddCollection = (bool (*)(void *, PARCCollection *))NULL,
+ .AddCollectionAtIndex = (bool (*)(void *, int index, PARCCollection *))NULL,
+ .Clear = (void (*)(void *))parcArrayList_Clear,
+ .Contains = (bool (*)(const void *, const PARCObject *))NULL,
+ .ContainsCollection = (bool (*)(const void *, const PARCCollection *))NULL,
+ .Copy = (void * (*)(const PARCList *))parcArrayList_Copy,
+ .Destroy = (void (*)(void **))parcArrayList_Destroy,
+ .Equals = (bool (*)(const void *, const void *))parcArrayList_Equals,
+ .GetAtIndex = (void * (*)(const void *, size_t))parcArrayList_Get,
+ .HashCode = (PARCHashCode (*)(const void *))NULL,
+ .IndexOf = (size_t (*)(const void *, const PARCObject *element))NULL,
+ .IsEmpty = (bool (*)(const void *))parcArrayList_IsEmpty,
+ .LastIndexOf = (size_t (*)(void *, const PARCObject *element))NULL,
+ .Remove = (bool (*)(void *, const PARCObject *))NULL,
+ .RemoveAtIndex = (void * (*)(PARCList *, size_t))parcArrayList_RemoveAtIndex,
+ .RemoveCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .RetainCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .SetAtIndex = (void * (*)(void *, size_t index, void *))parcArrayList_Set,
+ .Size = (size_t (*)(const void *))parcArrayList_Size,
+ .SubList = (PARCList * (*)(const void *, size_t, size_t))NULL,
+ .ToArray = (void** (*)(const void *))NULL,
+};
+
+struct parc_array_list {
+ void **array;
+ size_t numberOfElements;
+ size_t limit;
+ bool (*equalsElement)(void *x, void *y);
+ void (*destroyElement)(void **elementAddress);
+};
+
+static size_t
+_remaining(const PARCArrayList *array)
+{
+ return array->limit - array->numberOfElements;
+}
+
+static PARCArrayList *
+_ensureCapacity(PARCArrayList *array, size_t newCapacity)
+{
+ void *newArray = parcMemory_Reallocate(array->array, newCapacity * sizeof(void *));
+
+ if (newArray == NULL) {
+ return NULL;
+ }
+ array->array = newArray;
+ array->limit = newCapacity;
+
+ return array;
+}
+
+static PARCArrayList *
+_ensureRemaining(PARCArrayList *array, size_t remnant)
+{
+ assertNotNull(array, "Parameter must be a non-null PARCArrayList pointer.");
+
+ if (_remaining(array) < remnant) {
+ size_t newCapacity = parcArrayList_Size(array) + remnant;
+ return _ensureCapacity(array, newCapacity);
+ }
+ return array;
+}
+
+bool
+parcArrayList_IsValid(const PARCArrayList *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->numberOfElements == 0 ? true : instance->array != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcArrayList_AssertValid(const PARCArrayList *instance)
+{
+ trapIllegalValueIf(instance == NULL, "Parameter must be a non-null PARC_ArrayList pointer.");
+ assertTrue(instance->numberOfElements == 0 ? true : instance->array != NULL, "PARC_ArrayList size is inconsistent.");
+}
+
+static PARCArrayList *
+_parcArrayList_Init(PARCArrayList *arrayList,
+ size_t nElements,
+ size_t limit,
+ void **array,
+ bool (*equalsElement)(void *x, void *y),
+ void (*destroyElement)(void **elementAddress))
+{
+ if (arrayList != NULL) {
+ arrayList->array = array;
+ arrayList->numberOfElements = nElements;
+ arrayList->limit = limit;
+ arrayList->equalsElement = equalsElement;
+ arrayList->destroyElement = destroyElement;
+ }
+ return arrayList;
+}
+
+PARCArrayList *
+parcArrayList_Create(void (*destroyElement)(void **element))
+{
+ PARCArrayList *result = parcMemory_AllocateAndClear(sizeof(PARCArrayList));
+ assertNotNull(result, "Memory allocation of PARCArrayList failed");
+
+ return _parcArrayList_Init(result, 0, 0, NULL, NULL, destroyElement);
+}
+
+PARCArrayList *
+parcArrayList_Create_Capacity(bool (*equalsElement)(void *x, void *y), void (*destroyElement)(void **element), size_t size)
+{
+ PARCArrayList *result = parcMemory_AllocateAndClear(sizeof(PARCArrayList));
+ assertNotNull(result, "Memory allocation of PARCArrayList failed");
+
+ _parcArrayList_Init(result, 0, 0, NULL, equalsElement, destroyElement);
+
+ if (result != NULL) {
+ _ensureRemaining(result, size);
+ }
+
+ return result;
+}
+
+bool
+parcArrayList_Add(PARCArrayList *array, const void *pointer)
+{
+ parcArrayList_OptionalAssertValid(array);
+
+ if (_ensureRemaining(array, 1) == NULL) {
+ trapOutOfMemory("Cannot increase space for PARCArrayList.");
+ }
+ array->array[array->numberOfElements++] = (void *) pointer;
+
+ return true;
+}
+
+PARCArrayList *
+parcArrayList_AddAll(PARCArrayList *array, void *argv[], size_t argc)
+{
+ for (size_t i = 0; i < argc; i++) {
+ parcArrayList_Add(array, argv[i]);
+ }
+
+ return array;
+}
+
+bool
+parcArrayList_IsEmpty(const PARCArrayList *list)
+{
+ parcArrayList_OptionalAssertValid(list);
+
+ return list->numberOfElements == 0;
+}
+
+bool
+parcArrayList_Equals(const PARCArrayList *a, const PARCArrayList *b)
+{
+ bool result = true;
+
+ if (a != b) {
+ if (a == NULL || b == NULL) {
+ result = false;
+ } else if (a->numberOfElements != b->numberOfElements) {
+ result = false;
+ } else {
+ for (size_t i = 0; i < a->numberOfElements; i++) {
+ if (a->equalsElement != NULL) {
+ if (!a->equalsElement(a->array[i], b->array[i])) {
+ result = false;
+ break;
+ }
+ } else {
+ if (a->array[i] != b->array[i]) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void *
+parcArrayList_RemoveAtIndex(PARCArrayList *array, size_t index)
+{
+ trapOutOfBoundsIf(index >= array->numberOfElements, "Index must be within the range [0, %zu)", array->numberOfElements);
+
+ void *element = array->array[index];
+
+ // Adjust the list to elide the element.
+ for (size_t i = index; i < array->numberOfElements - 1; i++) {
+ array->array[i] = array->array[i + 1];
+ }
+ array->numberOfElements--;
+
+ return element;
+}
+
+void
+parcArrayList_Set(const PARCArrayList *array, size_t index, void *pointer)
+{
+ trapOutOfBoundsIf(index >= array->numberOfElements, "Index must be within the range [0, %zu)", array->numberOfElements);
+
+ array->array[index] = pointer;
+}
+
+void *
+parcArrayList_Get(const PARCArrayList *array, size_t index)
+{
+ trapOutOfBoundsIf(index >= array->numberOfElements, "Index must be within the range [0, %zu)", array->numberOfElements);
+
+ return array->array[index];
+}
+
+void *
+parcArrayList_Peek(const PARCArrayList *list)
+{
+ return parcArrayList_Get(list, parcArrayList_Size(list) - 1);
+}
+
+size_t
+parcArrayList_Size(const PARCArrayList *pointerArray)
+{
+ return pointerArray->numberOfElements;
+}
+
+void
+parcArrayList_Destroy(PARCArrayList **arrayPtr)
+{
+ assertNotNull(arrayPtr, "Parameter must be a non-null pointer to a PARC_ArrayList pointer.");
+
+ PARCArrayList *array = *arrayPtr;
+
+ parcArrayList_OptionalAssertValid(array);
+
+ assertTrue(array->numberOfElements == 0 ? true : array->array != NULL, "PARC_ArrayList is inconsistent.");
+
+ if (array->destroyElement != NULL) {
+ for (size_t i = 0; i < array->numberOfElements; i++) {
+ if (array->array[i] != NULL) {
+ array->destroyElement(&array->array[i]);
+ }
+ }
+ }
+
+ if (array->array != NULL) {
+ parcMemory_Deallocate((void **) &(array->array));
+ }
+
+ parcMemory_Deallocate((void **) &array);
+ *arrayPtr = 0;
+}
+
+PARCArrayList *
+parcArrayList_Copy(const PARCArrayList *original)
+{
+ parcArrayList_OptionalAssertValid(original);
+
+ PARCArrayList *result = parcArrayList_Create(original->destroyElement);
+
+ if (result != NULL) {
+ for (size_t i = 0; i < original->numberOfElements; i++) {
+ parcArrayList_Add(result, original->array[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+parcArrayList_StdlibFreeFunction(void **elementPtr)
+{
+ if (elementPtr != NULL) {
+ free(*elementPtr);
+ *elementPtr = 0;
+ }
+}
+
+void
+parcArrayList_PARCMemoryFreeFunction(void **elementPtr)
+{
+ if (elementPtr != NULL) {
+ parcMemory_Deallocate((void **) elementPtr);
+ *elementPtr = 0;
+ }
+}
+
+PARCArrayList *
+parcArrayList_RemoveAndDestroyAtIndex(PARCArrayList *array, size_t index)
+{
+ parcArrayList_OptionalAssertValid(array);
+
+ assertTrue(index < array->numberOfElements, "Index must be ( 0 <= index < %zd). Actual=%zd", array->numberOfElements, index);
+
+ if (index < array->numberOfElements) {
+ // Destroy the element at the given index.
+ if (array->destroyElement != NULL) {
+ array->destroyElement(&array->array[index]);
+ }
+
+ // Adjust the list to elide the element.
+ for (size_t i = index; i < array->numberOfElements - 1; i++) {
+ array->array[i] = array->array[i + 1];
+ }
+ array->numberOfElements--;
+ }
+
+ return array;
+}
+
+PARCArrayList *
+parcArrayList_InsertAtIndex(PARCArrayList *array, size_t index, const void *pointer)
+{
+ parcArrayList_OptionalAssertValid(array);
+ size_t length = parcArrayList_Size(array);
+
+ assertTrue(index <= array->numberOfElements, "You can't insert beyond the end of the list");
+
+ // Create space and grow the array if needed
+ _ensureRemaining(array, length + 1);
+ for (size_t i = index; i < length; i++) {
+ array->array[i + 1] = array->array[i];
+ }
+ array->numberOfElements++;
+
+ array->array[index] = (void *) pointer;
+
+ return array;
+}
+
+void *
+parcArrayList_Pop(PARCArrayList *array)
+{
+ return parcArrayList_RemoveAtIndex(array, parcArrayList_Size(array) - 1);
+}
+
+void
+parcArrayList_Clear(PARCArrayList *array)
+{
+ while (!parcArrayList_IsEmpty(array)) {
+ parcArrayList_RemoveAndDestroyAtIndex(array, parcArrayList_Size(array) - 1);
+ }
+}
diff --git a/libparc/parc/algol/parc_ArrayList.h b/libparc/parc/algol/parc_ArrayList.h
new file mode 100644
index 00000000..1e2be6b0
--- /dev/null
+++ b/libparc/parc/algol/parc_ArrayList.h
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_ArrayList.h
+ * @ingroup datastructures
+ * @brief A dynamic array of void * pointers.
+ *
+ * This module implements a dynamic array of simple void pointers.
+ * Users can create an empty array, or preprovisioned with an initial capacity of N elements.
+ *
+ */
+#ifndef libparc_parc_ArrayList_h
+#define libparc_parc_ArrayList_h
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Iterator.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcArrayList_OptionalAssertValid(_instance_)
+#else
+# define parcArrayList_OptionalAssertValid(_instance_) parcArrayList_AssertValid(_instance_)
+#endif
+
+struct parc_array_list;
+typedef struct parc_array_list PARCArrayList;
+
+/**
+ * The mapping of a `PARCArrayList` to the generic `PARCList`.
+ */
+extern PARCListInterface *PARCArrayListAsPARCList;
+
+/**
+ * Determine if a `PARCArrayList` is valid.
+ *
+ * @param [in] instance A pointer to a PARCArrayList instance.
+ *
+ * @return true The instance is valid.
+ * @return true The instance is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *list = parcArrayList_Create(NULL);
+ * if (parcArrayList_IsValid(list)) {
+ * printf("The list is valid.");
+ * }
+ * parcArrayList_Destroy((list);
+ * @endcode
+ */
+bool parcArrayList_IsValid(const PARCArrayList *instance);
+
+/**
+ * Assert that a `PARCArrayList` is valid.
+ *
+ * @param [in] instance A pointer to a PARCArrayList instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *list = parcArrayList_Create(NULL);
+ *
+ * parcArrayList_AssertValid(list);
+ *
+ * parcArrayList_Destroy((list);
+ * @endcode
+ */
+void parcArrayList_AssertValid(const PARCArrayList *instance);
+
+/**
+ * Add an element to the given PARCArrayList.
+ *
+ * If the PARCArrayList was constructed with a destroyer,
+ * the pointer will be destroyed when element is removed or the list is destroyed.
+ *
+ * @param [in] array A pointer to a `PARCArrayList`.
+ * @param [in] pointer A void pointer to the item to be added to the list.
+ *
+ * @return True If the value was successfully added to the list.
+ * @return False Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * bool wasAdded = parcArrayList_Add(array, elements);
+ * printf("Successfully added the base pointer? %d\n", wasAdded);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+bool parcArrayList_Add(PARCArrayList *array, const void *pointer);
+
+/**
+ * Add all of the pointers in the given array of pointers to the `PARCArrayList`.
+ *
+ * This is synonymous with calling {@link parcArrayList_Add()} multiple times
+ *
+ * @param [in] array A pointer to `PARCArrayList`.
+ * @param [in] argv A pointer to the base list of pointers.
+ * @param [in] argc The number of items to add to the list, starting from the abse void pointer.
+ *
+ * @return A pointer to the modified PARCArrayList.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_AddAll(PARCArrayList *array, void **argv, size_t argc);
+
+/**
+ * Remove an element at a specific index from a `PARCArrayList`.
+ *
+ * The element is destroyed via the function provided when calling {@link parcArrayList_Create()}.
+ * The index must be 0 <= index < length.
+ *
+ * @param [in,out] array A pointer to `PARCArrayList`.
+ * @param [in] index The index of the element to remove and destroy.
+ *
+ * @return A pointer to the modified `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ * parcArrayList_RemoveAndDestroyAtIndex(array, 0);
+ *
+ * size_t size = parcArrayList_Size(array);
+ * // size will now be three
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_RemoveAndDestroyAtIndex(PARCArrayList *array, size_t index);
+
+/**
+ * Return the element at index. Remove the element from the array.
+ *
+ * The index must be 0 <= index < length.
+ *
+ * @param [in,out] array A pointer to a `PARCArrayList` instance.
+ * @param [in] index The index of the element to remove.
+ *
+ * @return void* A pointer (void *) to the element that was removed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ * void *firstString = parcArrayList_RemoveAtIndex(array, 0);
+ *
+ * printf("First string: %s\n", firstString);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void *parcArrayList_RemoveAtIndex(PARCArrayList *array, size_t index);
+
+/**
+ * Insert an element at the index location. Elements will be moved up if required.
+ *
+ * You may not insert beyond the list end. (You can insert at the end, but not any more).
+ *
+ * @param [in,out] array A `PARCArrayList`
+ * @param [in] pointer A pointer to the element to insert
+ * @param [in] index An index in the `PARCArrayList`
+ * @return A pointer to the modified `PARCArrayList`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ *
+ * parcArrayList_InsertAtIndex(array, strdup("a"), 0);
+ * void *firstString = parcArrayList_RemoveAtIndex(array, 0);
+ * printf("First string is 'a': %s\n", firstString);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_InsertAtIndex(PARCArrayList *array, size_t index, const void *pointer);
+
+/**
+ * Create an instance of an empty `PARCArrayList`.
+ *
+ * @param [in] destroyElement
+ * A pointer to a function that will destroy (or equivalent) the element pointed to by `element`
+ *
+ * @return A pointer to the new `PARCArrayList` instance, or NULL if no memory could be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * ...
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_Create(void (*destroyElement)(void **elementAddress));
+
+/**
+ * Create an instance of a PARCArrayList pre-provisioned to contain the specified number of elements.
+ *
+ * @param [in] equalsElement
+ * A pointer to a function that will determine equality between two elements in the array.
+ * @param [in] destroyElement
+ * A pointer to a function that will destroy (or equivalent) the element pointed to by <code>element</code>
+ * @param [in] size
+ * The number of initial elements to provision for.
+ * @return A pointer to a new `PARCArrayList` instance, or NULL if no memory could be allocated.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcArrayList_Create_Capacity(bool (*equalsElement)(void *x, void *y), void (*destroyElement)(void **elementAddress), size_t size);
+
+/**
+ * Copy a `PARCArrayList` instance.
+ *
+ * Create a new `PARCArrayList` instance with the same structure and content as the original.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance to copy.
+ *
+ * @return A pointer to a new `PARCArrayList` instance with a copy of the original, or NULL if no memory could be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * parcArrayList_InsertAtIndex(array, strdup("a"), 0);
+ *
+ * PARCArrayList *sameList = parcArrayList_Copy(array);
+ *
+ * if (parcArrayList_Equals(array, sameList)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_Copy(const PARCArrayList *array);
+
+/**
+ * Destroy a `PARCArrayList` instance.
+ *
+ * Destroy the given `PARCArrayList` by freeing all memory used by it.
+ *
+ * @param [in,out] arrayPtr A pointer to the pointer of the `PARCArrayList` to be destroyed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void parcArrayList_Destroy(PARCArrayList **arrayPtr);
+
+/**
+ * Set an element from the given `PARCArrayList` at a specified index to a value.
+ *
+ * The index must be 0 <= index < length.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance.
+ * @param [in] index The index into the `PARCArrayList` instance.
+ * @param [in] pointer A void pointer to the item to be assigned to the index
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * bool wasAdded = parcArrayList_Add(array, elements);
+ * // how to free the pointer at index 1 without deallocating the slot? XXX
+ * parcArrayList_Set(array, 1, strdup("d");
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void parcArrayList_Set(const PARCArrayList *array, size_t index, void *pointer);
+
+/**
+ * Get an element from the given `PARCArrayList` at a specified index.
+ *
+ * The index must be 0 <= index < length.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance.
+ * @param [in] index The index into the `PARCArrayList` instance.
+ *
+ * @return A pointer (void *) to the element in the list.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ * void *firstString = parcArrayList_Get(array, 0);
+ *
+ * printf("First string: %s\n", firstString);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void *parcArrayList_Get(const PARCArrayList *array, size_t index);
+
+/**
+ * Return the number of elements in the given `PARCArrayList`.
+ *
+ * The size is the number of elements, NOT the size in bytes of all elements maintained in the list.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance.
+ *
+ * @return A size_t of the number of elements in the given `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ *
+ * size_t size = parcArrayList_Size(array);
+ * printf("Size =?= 3: %d\n", size == 3);
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+size_t parcArrayList_Size(const PARCArrayList *array);
+
+/**
+ * Determine if two `PARCArrayList` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCArrayList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, parcArrayList_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcArrayList_Equals(x, y) must return true if and only if
+ * parcArrayList_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcArrayList_Equals(x, y) returns true and
+ * parcArrayList_Equals(y, z) returns true,
+ * then parcArrayList_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcArrayList_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcArrayList_Equals(x, NULL)) must return false.
+ *
+ * @param [in] a The first `PARCArrayList` instance.
+ * @param [in] b The second `PARCArrayList` instance.
+ *
+ * @return true the given PARCArrayList instances are equal.
+ * @return false the given PARCArrayList instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *a = parcArrayList_Create();
+ * PARCArrayList *b = parcArrayList_Create();
+ *
+ * if (parcArrayList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcArrayList_Equals(const PARCArrayList *a, const PARCArrayList *b);
+
+/**
+ * Standard library free(3) wrapper for use as a destructor function for elements of a `PARCArrayList`.
+ *
+ * The create functions for `PARCArrayList` have an input parameter that is a pointer to a function that
+ * will be called for each element when the `PARCArrayList` is destroyed, and when an element is removed via
+ * {@link parcArrayList_RemoveAndDestroyAtIndex}.
+ * This destroy function has a different calling signature than the standard library's free(3) function.
+ * This function is a wrapper providing the correct facade for the standard library free(3) function.
+ *
+ * @param [in,out] element A pointer to the element to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcArrayList_StdlibFreeFunction(void **element);
+
+/**
+ * PARC_Memory free() wrapper for use as a destructor function for elements of a `PARCArrayList`.
+ *
+ * The create functions for `PARCArrayList` have an input parameter that is a pointer to a function that
+ * will be called for each element when the `PARCArrayList` is destroyed, and when an element is removed via
+ * {@link parcArrayList_RemoveAndDestroyAtIndex}.
+ * This destroy function has a different calling signature than the PARC_Memory's free(3) function.
+ * This function is a wrapper providing the correct facade for the PARC_Memory's free(3) function.
+ *
+ * @param [in,out] elementPtr A pointer to the element to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcArrayList_PARCMemoryFreeFunction(void **elementPtr);
+
+/**
+ * Tests if this list is empty.
+ *
+ *
+ * @param [in] list A pointer to the `PARCArrayList` to test.
+ * @return true if the stack is empty.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcArrayList_IsEmpty(const PARCArrayList *list);
+
+/**
+ * Returns a pointer to object at the top of this stack without removing it from the stack.
+ *
+ * @param [in] list A pointer to `PARCArrayList`.
+ * @return A pointer to the first element of the `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcArrayList_Peek(const PARCArrayList *list);
+
+/**
+ * Removes the object at the top of this stack and returns that object as the value of this function.
+ *
+ * @param [in,out] list A pointer to the `PARCArrayList`.
+ * @return A pointer to what was the first element of the `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcArrayList_Pop(PARCArrayList *list);
+
+/**
+ * Removes all objects from this stack.
+ *
+ * @param [in,out] list A pointer to the `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcArrayList_Clear(PARCArrayList *list);
+
+/**
+ * Pushes an item onto the top of this stack.
+ *
+ * @param [in,out] list A pointer to a `PARCArrayList`.
+ * @param [in] item A pointer to an element to be added to the `PARCArrayList`.
+ * @return A pointer to the item just pushed on to the `PARCArrayLis.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcArrayList_Push(PARCArrayList *list, void *item);
+
+/**
+ * Returns the 1-based position where an object is on this stack.
+ *
+ * @param [in] list A pointer to `PARCArrayList`.
+ * @param [in] element A pointer to the element to locate in the `PARCArrayList`.
+ * @return int The index of the located element in the `PARCArrayList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcArrayList_Search(PARCArrayList *list, void *element);
+#endif // libparc_parc_ArrayList_h
diff --git a/libparc/parc/algol/parc_AtomicInteger.c b/libparc/parc/algol/parc_AtomicInteger.c
new file mode 100755
index 00000000..b32a698f
--- /dev/null
+++ b/libparc/parc/algol/parc_AtomicInteger.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <pthread.h>
+
+#include <parc/algol/parc_AtomicInteger.h>
+
+#ifdef USE_GCC_EXTENSIONS
+uint32_t
+parcAtomicInteger_Uint32IncrementGCC(uint32_t *value)
+{
+ return __sync_add_and_fetch(value, 1);
+}
+
+uint32_t
+parcAtomicInteger_Uint32DecrementGCC(uint32_t *value)
+{
+ return __sync_sub_and_fetch(value, 1);
+}
+
+uint64_t
+parcAtomicInteger_Uint64IncrementGCC(uint64_t *value)
+{
+ return __sync_add_and_fetch(value, 1);
+}
+
+uint64_t
+parcAtomicInteger_Uint64DecrementGCC(uint64_t *value)
+{
+ return __sync_sub_and_fetch(value, 1);
+}
+#endif
+
+
+// Since there is no per integer mutex, we must use something to protect an integer from multiple,
+// simultaneous competitors.
+// Unfortunately, this is an indiscrimiate mutex causing all atomic integer updates to be
+// serialized rather than each individually protected.
+static pthread_mutex_t _parcAtomicInteger_PthreadMutex = PTHREAD_MUTEX_INITIALIZER;
+
+uint32_t
+parcAtomicInteger_Uint32IncrementPthread(uint32_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value + 1;
+ uint32_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
+
+uint32_t
+parcAtomicInteger_Uint32DecrementPthread(uint32_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value - 1;
+ uint32_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
+
+uint64_t
+parcAtomicInteger_Uint64IncrementPthread(uint64_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value + 1;
+ uint64_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
+
+uint64_t
+parcAtomicInteger_Uint64DecrementPthread(uint64_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value - 1;
+ uint64_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
diff --git a/libparc/parc/algol/parc_AtomicInteger.h b/libparc/parc/algol/parc_AtomicInteger.h
new file mode 100755
index 00000000..729d9a01
--- /dev/null
+++ b/libparc/parc/algol/parc_AtomicInteger.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_AtomicInteger.h
+ * @ingroup threading
+ * @brief An integer value that may be updated automatically.
+ *
+ */
+#ifndef libparc_parc_AtomicInteger_h
+#define libparc_parc_AtomicInteger_h
+
+#include <stdint.h>
+
+/*
+ * If we are compiling with GCC or Clang, then
+ * we have some compiler extensions to make use of processer
+ * compare-and-swap and other kinds of synchronisation primitives.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define USE_GCC_EXTENSIONS 1
+#endif
+
+// Turn this off until the problem on the SMP machines is worked out, case 787.
+#undef USE_GCC_EXTENSIONS
+
+#ifdef USE_GCC_EXTENSIONS
+uint32_t parcAtomicInteger_Uint32IncrementGCC(uint32_t *value);
+
+uint32_t parcAtomicInteger_Uint32DecrementGCC(uint32_t *value);
+
+uint64_t parcAtomicInteger_Uint64IncrementGCC(uint64_t *value);
+
+uint64_t parcAtomicInteger_Uint64DecrementGCC(uint64_t *value);
+
+#define parcAtomicInteger_Uint32Increment parcAtomicInteger_Uint32IncrementGCC
+
+#define parcAtomicInteger_Uint32Decrement parcAtomicInteger_Uint32DecrementGCC
+
+#define parcAtomicInteger_Uint64Increment parcAtomicInteger_Uint64IncrementGCC
+
+#define parcAtomicInteger_Uint64Decrement parcAtomicInteger_Uint64DecrementGCC
+
+#else
+uint32_t parcAtomicInteger_Uint32IncrementPthread(uint32_t *value);
+
+uint32_t parcAtomicInteger_Uint32DecrementPthread(uint32_t *value);
+
+uint64_t parcAtomicInteger_Uint64IncrementPthread(uint64_t *value);
+
+uint64_t parcAtomicInteger_Uint64DecrementPthread(uint64_t *value);
+
+#define parcAtomicInteger_Uint32Increment parcAtomicInteger_Uint32IncrementPthread
+
+#define parcAtomicInteger_Uint32Decrement parcAtomicInteger_Uint32DecrementPthread
+
+#define parcAtomicInteger_Uint64Increment parcAtomicInteger_Uint64IncrementPthread
+
+#define parcAtomicInteger_Uint64Decrement parcAtomicInteger_Uint64DecrementPthread
+#endif
+#endif // libparc_parc_AtomicInteger_h
diff --git a/libparc/parc/algol/parc_Base64.c b/libparc/parc/algol/parc_Base64.c
new file mode 100755
index 00000000..38020479
--- /dev/null
+++ b/libparc/parc/algol/parc_Base64.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *
+ * Encode/decode base64. Encoding goes to one long line, no line breaks.
+ * Decoding will accept CRLF linebreaks in the data and skip them.
+ *
+ * Following the language of RFC 4648, encoding proceeds in a "quantum" of
+ * 3 bytes of plaintext to 4 bytes of encoded data. Decoding goes in
+ * a 4-byte quantum to 3-byte decoded data.
+ *
+ * If decoding fails (e.g. there's a non-base64 character), then the output
+ * buffer is rewound to the starting position and a failure is indicated.
+ *
+ * Decoding using a 256 byte table. Each byte of the 4-byte quantum is looked
+ * up and if its a valid character -- it resolves to a value 0..63, then that
+ * value is shifted to the right position in the output. Values CR and LF have
+ * the special token "_" in the table, which means "skip". That token has value
+ * ascii value 95, is we can detect it as outside base64. Similarly, all the
+ * invalid characters have the symbol "~", which is ascii 127.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Base64.h>
+#include <parc/algol/parc_Memory.h>
+
+const uint8_t base64code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+const uint8_t pad = '=';
+
+const uint8_t invalid = '~'; // has ascii value 127, outside base64
+const uint8_t skip = '_'; // has ascii value 95, outside the base64 values
+
+// an 256-entry table to lookup decode values. If the value is "invalid", then it's not
+// a base64 character.
+const uint8_t decodeTable[256] = {
+/* 0 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '_', '~', '~', '_', '~', '~',
+/* 16 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+/* 32 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', 62, '~', '~', '~', 63,
+/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, '~', '~', '~', '~', '~', '~',
+/* 64 */ '~', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, '~', '~', '~', '~', '~',
+/* 96 */ '~', 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, '~', '~', '~', '~', '~',
+/* 128 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~'
+};
+
+#define min(a, b) ((a < b) ? a : b)
+
+/**
+ * Encode the 3-byte quantum pointed to by <code>quantum</code> into 4 encoded characters.
+ * It includes `padLength` of pad necessary at the end.
+ */
+static void
+_encodeWithPad(PARCBufferComposer *output, const uint8_t *quantum, size_t padLength)
+{
+ assertTrue(padLength < 3, "Degenerate case -- should never pad all 3 bytes!");
+
+ unsigned index;
+
+ uint8_t paddedQuantum[] = { 0, 0, 0 };
+ memcpy(paddedQuantum, quantum, 3 - padLength);
+
+ for (index = 0; index < 4; index++) {
+ if (index + padLength < 4) {
+ /*
+ * The four base64 symbols fall in to these locations in the
+ * 3-byte input
+ *
+ * aaaaaabb | bbbbcccc | ccdddddd
+ *
+ * This switch statement, based on the "a" "b" "c" or "d" case
+ * extracts the corresponding 6 bits from its location in the
+ * byte aray.
+ */
+ int sixbit = 0;
+ switch (index) {
+ case 0: // aaaaaa
+ sixbit = paddedQuantum[0] >> 2;
+ break;
+
+ case 1: // bbbbbb
+ sixbit = ((paddedQuantum[0] & 0x03) << 4) | (paddedQuantum[1] >> 4);
+ break;
+
+ case 2: // cccccc
+ sixbit = ((paddedQuantum[1] & 0x0F) << 2) | (paddedQuantum[2] >> 6);
+ break;
+
+ case 3: // dddddd
+ sixbit = paddedQuantum[2] & 0x3F;
+ break;
+ }
+ uint8_t encodedChar = base64code[ sixbit ];
+ parcBufferComposer_PutUint8(output, encodedChar);
+ } else {
+ parcBufferComposer_PutUint8(output, pad);
+ }
+ }
+}
+
+/**
+ * Decode the 4-byte quantum of base64 to binary.
+ */
+static bool
+_decode(PARCBufferComposer *output, uint8_t *quantum)
+{
+ uint8_t threebytes[3] = { 0, 0, 0 };
+ size_t length_to_append = 0;
+
+ for (int index = 0; index < 4; index++) {
+ uint8_t c = quantum[index];
+ if (c != pad) {
+ uint8_t value = decodeTable[c];
+
+ // if its a non-base64 character, bail out of here
+ if (value == invalid) {
+ return false;
+ }
+
+ /*
+ * The four base64 symbols fall in to these locations in the
+ * final 3-byte output
+ *
+ * aaaaaabb | bbbbcccc | ccdddddd
+ */
+ switch (index) {
+ case 0: // aaaaaa
+ threebytes[0] |= value << 2;
+ break;
+
+ case 1: // bbbbbb
+ threebytes[0] |= (value & 0x30) >> 4;
+ threebytes[1] |= (value & 0x0F) << 4;
+
+ // we've finished threebytes[0]
+ length_to_append = 1;
+ break;
+
+ case 2: // cccccc
+ threebytes[1] |= value >> 2;
+ threebytes[2] |= (value & 0x03) << 6;
+
+ // we've finished threebytes[1]
+ length_to_append = 2;
+ break;
+
+ case 3: // dddddd
+ threebytes[2] |= value;
+
+ // we've finished threebytes[2]
+ length_to_append = 3;
+ break;
+ }
+ }
+ }
+
+ parcBufferComposer_PutArray(output, threebytes, length_to_append);
+ return true;
+}
+
+PARCBufferComposer *
+parcBase64_Encode(PARCBufferComposer *result, PARCBuffer *plainText)
+{
+ size_t remaining = parcBuffer_Remaining(plainText);
+ if (remaining > 0) {
+ const uint8_t *buffer = parcBuffer_Overlay(plainText, 0);
+ result = parcBase64_EncodeArray(result, remaining, buffer);
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcBase64_EncodeArray(PARCBufferComposer *output, size_t length, const uint8_t array[length])
+{
+ size_t offset = 0;
+
+ // Encode 3-byte tuples
+ while (offset < length) {
+ const uint8_t *quantum = array + offset;
+ size_t padLength = 3 - min(3, length - offset);
+ _encodeWithPad(output, quantum, padLength);
+ offset += 3;
+ }
+
+ return output;
+}
+
+PARCBufferComposer *
+parcBase64_Decode(PARCBufferComposer *output, PARCBuffer *encodedText)
+{
+ // We proceed in 4-byte blocks. All base-64 encoded data is a multiple of 4 bytes.
+ // If the length of encodedText is wrong, bail now
+
+ size_t remaining = parcBuffer_Remaining(encodedText);
+ const uint8_t *buffer = parcBuffer_Overlay(encodedText, remaining);
+ return parcBase64_DecodeArray(output, remaining, buffer);
+}
+
+PARCBufferComposer *
+parcBase64_DecodeString(PARCBufferComposer *output, const char *encodedString)
+{
+ const uint8_t *buffer = (const uint8_t *) encodedString;
+ size_t length = strlen(encodedString);
+ return parcBase64_DecodeArray(output, length, buffer);
+}
+
+PARCBufferComposer *
+parcBase64_DecodeArray(PARCBufferComposer *output, size_t length, const uint8_t array[length])
+{
+ size_t offset = 0;
+ bool success = true;
+
+ // if we need to rollback, this is where we go
+ PARCBuffer *outputBuffer = parcBufferComposer_GetBuffer(output);
+ size_t rewind_to = parcBuffer_Position(outputBuffer);
+
+ while (offset < length && success) {
+ // filter out line feeds and carrage returns
+ // parse the input in 4-byte quantums
+ size_t index = 0;
+ uint8_t quantum[4];
+
+ // reset success at the start of each loop. if we run out of input before
+ // we parse a full quantum, we'll fail the loop and rewind the output buffer.
+ success = false;
+
+ // 4 == quantum length for decode
+ while (index < 4 && offset < length) {
+ uint8_t c = array[offset];
+ uint8_t decoded = decodeTable[c];
+
+ if (decoded < 64 || c == pad) {
+ // this is an artifact from how the code was first written, so we
+ // pass the un-decoded character
+ quantum[index] = c;
+ index++;
+ offset++;
+ continue;
+ }
+
+ if (decoded == skip) {
+ offset++;
+ continue;
+ }
+
+ if (decoded == invalid) {
+ break;
+ }
+ }
+
+ if (index == 4) {
+ success = _decode(output, quantum);
+ }
+ }
+
+ if (!success) {
+ parcBuffer_SetPosition(outputBuffer, rewind_to);
+ return NULL;
+ }
+
+ return output;
+}
diff --git a/libparc/parc/algol/parc_Base64.h b/libparc/parc/algol/parc_Base64.h
new file mode 100644
index 00000000..7d60797a
--- /dev/null
+++ b/libparc/parc/algol/parc_Base64.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Base64.h
+ * @ingroup inputoutput
+ * @brief Encode/decode base64
+ *
+ * Encoding goes to one long line, no line breaks.
+ * Decoding will accept CRLF linebreaks in the data and skip them.
+ *
+ * Following the language of RFC 4648, encoding proceeds in a "quantum" of
+ * 3 bytes of plaintext to 4 bytes of encoded data. Decoding goes in
+ * a 4-byte quantum to 3-byte decoded data.
+ *
+ * If decoding fails (e.g. there's a non-base64 character), then the output
+ * buffer is rewound to the starting position and a failure is indicated.
+ *
+ * Decoding using a 256 byte table. Each byte of the 4-byte quantum is looked
+ * up and if its a valid character -- it resolves to a value 0..63, then that
+ * value is shifted to the right position in the output. Values CR and LF have
+ * the special token "_" in the table, which means "skip". That token has value
+ * ascii value 95, is we can detect it as outside base64. Similarly, all the
+ * invalid characters have the symbol "~", which is ascii 127.
+ *
+ */
+#ifndef libparc_parc_Base64_h
+#define libparc_parc_Base64_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+/**
+ * Encode the plaintext buffer to base64, as per RFC 4648, Section 4.
+ *
+ * The base64 encoding is appended to `output` at the current position, and `output` is returned.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the encoded @plainText is appended
+ * @param [in] plainText The text to encode and append to @p output
+ *
+ * @return A pointer to the @p output
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+PARCBufferComposer *parcBase64_Encode(PARCBufferComposer *output, PARCBuffer *plainText);
+
+/**
+ * Encode the array to base64.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the encoded @p array is appended
+ * @param [in] length The length of the Array to be encoded
+ * @param array The array to be encoded and appended to @p output
+ *
+ * @return A pointer to the @p output
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_EncodeArray(PARCBufferComposer *output, size_t length, const uint8_t *array);
+
+/**
+ * Base64 decode the @p encodedText and append the result to @p output,
+ * which is returned by the function.
+ *
+ * If the @p encodedText cannot be base64 decoded,
+ * @p output is reset to the starting position and the function returns NULL.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the decoded @p encodedText is appended
+ * @param [in] encodedText The array to be decoded and appended to @p output
+ *
+ * @return A pointer to the @p output, or NULL if the @p encodedText cannot be base64 decoded
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_Decode(PARCBufferComposer *output, PARCBuffer *encodedText);
+
+/**
+ * Base64 decode the string, using strlen() to get the length.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the decoded @p encodedText is appended
+ * @param [in] encodedString The string to be decoded and appended to @p output
+ *
+ * @return A pointer to the @p output, or NULL if the @p encodedString cannot be base64 decoded
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_DecodeString(PARCBufferComposer *output, const char *encodedString);
+
+/**
+ * Base64 decode the array.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the decoded @p array is appended
+ * @param [in] length The size of the array.
+ * @param [in] array The array to be decoded and appended to @p output
+ *
+ * @return A pointer to the @p output, or NULL if the @p encodedString cannot be base64 decoded
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_DecodeArray(PARCBufferComposer *output, size_t length, const uint8_t *array);
+#endif // libparc_parc_Base64_h
diff --git a/libparc/parc/algol/parc_BitVector.c b/libparc/parc/algol/parc_BitVector.c
new file mode 100755
index 00000000..578fd102
--- /dev/null
+++ b/libparc/parc/algol/parc_BitVector.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_BitVector.h>
+#include <parc/algol/parc_Memory.h>
+
+#define BITS_PER_BYTE 8
+#define DEFAULT_BITARRAY_SIZE 1
+#define MAX_BIT_VECTOR_INDEX 8192
+
+struct PARCBitVector {
+ // the number of bits allocated.
+ unsigned bitLength;
+
+ // we track the number of "1"s set for fast computation
+ // <code>parcBitVector_NumberOfBitsSet()</code>
+ unsigned numberOfBitsSet;
+
+ // optimize case where only one bit is set.
+ unsigned firstBitSet;
+
+ // our backing memory.
+ uint8_t *bitArray;
+
+ // Fill value to be used when extending a vector
+ int fillValue;
+};
+
+static void
+_destroy(PARCBitVector **parcBitVector)
+{
+ parcMemory_Deallocate(&((*parcBitVector)->bitArray));
+}
+
+parcObject_ExtendPARCObject(PARCBitVector, _destroy, parcBitVector_Copy, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcBitVector, PARCBitVector);
+
+parcObject_ImplementRelease(parcBitVector, PARCBitVector);
+
+PARCBitVector *
+parcBitVector_Create(void)
+{
+ PARCBitVector *parcBitVector = parcObject_CreateInstance(PARCBitVector);
+ assertNotNull(parcBitVector, "parcObject_CreateInstance returned NULL");
+
+ parcBitVector->bitArray = parcMemory_AllocateAndClear(DEFAULT_BITARRAY_SIZE);
+ assertNotNull(parcBitVector->bitArray, "parcMemory_AllocateAndClear(%d) returned NULL", DEFAULT_BITARRAY_SIZE);
+ parcBitVector->bitLength = DEFAULT_BITARRAY_SIZE * BITS_PER_BYTE;
+ parcBitVector->numberOfBitsSet = 0;
+ parcBitVector->firstBitSet = -1;
+ parcBitVector->fillValue = 0;
+
+ return parcBitVector;
+}
+
+PARCBitVector *
+parcBitVector_Copy(const PARCBitVector *source)
+{
+ PARCBitVector *parcBitVector = parcObject_CreateInstance(PARCBitVector);
+ assertNotNull(parcBitVector, "parcObject_CreateInstance returned NULL");
+
+ size_t byteLength = source->bitLength / BITS_PER_BYTE;
+ parcBitVector->bitArray = parcMemory_Allocate(byteLength);
+ memcpy(parcBitVector->bitArray, source->bitArray, byteLength);
+ parcBitVector->bitLength = source->bitLength;
+ parcBitVector->numberOfBitsSet = source->numberOfBitsSet;
+ parcBitVector->firstBitSet = source->firstBitSet;
+ parcBitVector->fillValue = source->fillValue;
+
+ return parcBitVector;
+}
+
+bool
+parcBitVector_Equals(const PARCBitVector *a, const PARCBitVector *b)
+{
+ bool equal = ((a->numberOfBitsSet == b->numberOfBitsSet) &&
+ (a->firstBitSet == b->firstBitSet));
+
+ if (equal) {
+ int byteLength = a->bitLength / BITS_PER_BYTE;
+ if ((a->bitLength != b->bitLength) &&
+ (b->bitLength < a->bitLength)) {
+ byteLength = b->bitLength / BITS_PER_BYTE;
+ }
+ equal = (memcmp(a->bitArray, b->bitArray, byteLength) == 0);
+ }
+
+ return equal;
+}
+
+static void
+_parc_bit_vector_resize(PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertNotNull(parcBitVector, "_parc_bit_vector_resize passed a NULL parcBitVector");
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "_parc_bit_vector_resize passed a bit index that's too large");
+
+ unsigned neededBits = bit + 1;
+ if (neededBits > parcBitVector->bitLength) {
+ int newSize = (neededBits / BITS_PER_BYTE) + ((neededBits % BITS_PER_BYTE) ? 1 : 0);
+ int oldSize = (parcBitVector->bitLength / BITS_PER_BYTE) + ((parcBitVector->bitLength % BITS_PER_BYTE) ? 1 : 0);
+
+ uint8_t *newArray = parcMemory_Reallocate(parcBitVector->bitArray, newSize);
+ assertTrue(newArray, "parcMemory_Reallocate(%d) failed", newSize);
+ // Reallocate does not guarantee that additional memory is zero-filled.
+ memset((void *) &(newArray[oldSize]), parcBitVector->fillValue, newSize - oldSize);
+
+ parcBitVector->bitArray = newArray;
+ assertNotNull(newArray, "parcMemory_Reallocate(%d) returned NULL", newSize);
+ parcBitVector->bitLength = newSize * BITS_PER_BYTE;
+ }
+}
+
+int
+parcBitVector_Get(const PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "parcBitVector_Set passed a bit index that's too large");
+
+ if ((parcBitVector == NULL) || (bit >= parcBitVector->bitLength)) {
+ return -1;
+ }
+
+ int byte = bit / BITS_PER_BYTE;
+ int bitInByte = bit % BITS_PER_BYTE;
+ if ((parcBitVector->bitArray[byte] & (1 << bitInByte))) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+parcBitVector_Set(PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertNotNull(parcBitVector, "parcBitVector_Set passed a NULL parcBitVector");
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "parcBitVector_Set passed a bit index that's too huge");
+ if (bit >= parcBitVector->bitLength) {
+ _parc_bit_vector_resize(parcBitVector, bit);
+ }
+ int byte = bit / BITS_PER_BYTE;
+ int bitInByte = bit % BITS_PER_BYTE;
+ if (!(parcBitVector->bitArray[byte] & (1 << bitInByte))) {
+ parcBitVector->bitArray[byte] |= (1 << bitInByte);
+ parcBitVector->numberOfBitsSet++;
+ }
+ if ((parcBitVector->firstBitSet == -1) || (bit < parcBitVector->firstBitSet)) {
+ parcBitVector->firstBitSet = bit;
+ }
+}
+
+void
+parcBitVector_SetVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToSet)
+{
+ assertNotNull(parcBitVector, "parcBitVector_SetVector passed a NULL parcBitVector");
+ assertNotNull(parcBitVector, "parcBitVector_SetVector passed a NULL vector of bits to set");
+ int settingBit = 0;
+ for (int i = 0; i < bitsToSet->numberOfBitsSet; i++) {
+ settingBit = parcBitVector_NextBitSet(bitsToSet, settingBit);
+ assertTrue(settingBit != -1, "Number of bits claimed set inconsistent with bits found");
+ parcBitVector_Set(parcBitVector, settingBit);
+ settingBit++;
+ }
+}
+
+void
+parcBitVector_Reset(PARCBitVector *parcBitVector)
+{
+ parcBitVector->numberOfBitsSet = 0;
+ parcBitVector->firstBitSet = -1;
+ parcBitVector->fillValue = 0;
+ memset(parcBitVector->bitArray, parcBitVector->fillValue, parcBitVector->bitLength / BITS_PER_BYTE);
+}
+
+
+void
+parcBitVector_Clear(PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertNotNull(parcBitVector, "parcBitVector_Clear passed a NULL parcBitVector");
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "parcBitVector_Clear passed a bit index that's too huge");
+ if (bit > parcBitVector->bitLength) {
+ _parc_bit_vector_resize(parcBitVector, bit);
+ }
+ int byte = bit / BITS_PER_BYTE;
+ int bitInByte = bit % BITS_PER_BYTE;
+ if (parcBitVector->bitArray[byte] & (1 << bitInByte)) {
+ parcBitVector->bitArray[byte] &= ~(1 << bitInByte);
+ parcBitVector->numberOfBitsSet--;
+ }
+ if (bit == parcBitVector->firstBitSet) {
+ parcBitVector->firstBitSet = parcBitVector_NextBitSet(parcBitVector, bit + 1);
+ }
+}
+
+void
+parcBitVector_ClearVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToClear)
+{
+ assertNotNull(parcBitVector, "parcBitVector_ClearVector passed a NULL parcBitVector");
+ assertNotNull(bitsToClear, "parcBitVector_ClearVector passed a NULL for vector of bitsToClear");
+
+ // If we're clearing ourself, we just need a reset
+ if (parcBitVector == bitsToClear) {
+ parcBitVector_Reset(parcBitVector);
+ return;
+ }
+
+ int clearingBit = 0;
+ for (int i = 0; i < bitsToClear->numberOfBitsSet; i++) {
+ clearingBit = parcBitVector_NextBitSet(bitsToClear, clearingBit);
+ // only clear up to the end of the original vector
+ if (clearingBit >= parcBitVector->bitLength) {
+ return;
+ }
+ if (clearingBit != -1) {
+ parcBitVector_Clear(parcBitVector, clearingBit);
+ }
+ clearingBit++;
+ }
+}
+
+unsigned
+parcBitVector_NumberOfBitsSet(const PARCBitVector *parcBitVector)
+{
+ return parcBitVector->numberOfBitsSet;
+}
+
+unsigned
+parcBitVector_NextBitSet(const PARCBitVector *parcBitVector, unsigned startFrom)
+{
+ if (startFrom >= parcBitVector->bitLength) {
+ return -1;
+ }
+ if (startFrom <= parcBitVector->firstBitSet) {
+ return parcBitVector->firstBitSet;
+ }
+ int byte = startFrom / BITS_PER_BYTE;
+ int bitInByte = startFrom % BITS_PER_BYTE;
+ int allocatedBytes = ((parcBitVector->bitLength) / BITS_PER_BYTE);
+ for (; byte < allocatedBytes; byte++) {
+ if (parcBitVector->bitArray[byte]) {
+ for (; bitInByte < BITS_PER_BYTE; bitInByte++) {
+ if (parcBitVector->bitArray[byte] & (1 << bitInByte)) {
+ return (byte * BITS_PER_BYTE) + bitInByte;
+ }
+ }
+ }
+ bitInByte = 0;
+ }
+ return -1;
+}
+
+bool
+parcBitVector_Contains(const PARCBitVector *parcBitVector, const PARCBitVector *testVector)
+{
+ bool result = true;
+
+ int testBit = 0;
+ for (int i = 0; i < testVector->numberOfBitsSet; i++, testBit++) {
+ testBit = parcBitVector_NextBitSet(testVector, testBit);
+ if (parcBitVector_Get(parcBitVector, testBit) != 1) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
+
+char *
+parcBitVector_ToString(const PARCBitVector *parcBitVector)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ int nextBitSet = 0;
+ parcBufferComposer_Format(composer, "[ ");
+ for (int index = parcBitVector_NumberOfBitsSet(parcBitVector); index; index--) {
+ nextBitSet = parcBitVector_NextBitSet(parcBitVector, nextBitSet);
+ parcBufferComposer_Format(composer, "%d ", nextBitSet);
+ nextBitSet++;
+ }
+ parcBufferComposer_Format(composer, "]");
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+
+ return result;
+}
+
+PARCBitVector *
+parcBitVector_Or(const PARCBitVector *first, const PARCBitVector *second)
+{
+ PARCBitVector *result = NULL;
+
+ if (first != NULL) {
+ result = parcBitVector_Copy(first);
+ if (second != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(second, bit)) >= 0; bit++) {
+ parcBitVector_Set(result, bit);
+ }
+ }
+ } else if (second != NULL) {
+ result = parcBitVector_Copy(second);
+ } else { // both null, or is empty
+ result = parcBitVector_Create();
+ }
+
+ return result;
+}
+
+PARCBitVector *
+parcBitVector_And(const PARCBitVector *first, const PARCBitVector *second)
+{
+ PARCBitVector *result = parcBitVector_Create();
+
+ if (second == NULL) {
+ if (first != NULL) {
+ return result;
+ }
+ }
+
+ if (first != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(first, bit)) >= 0; bit++) {
+ if (parcBitVector_Get(second, bit) == 1) {
+ parcBitVector_Set(result, bit);
+ }
+ }
+ }
+
+ return result;
+}
+
+static PARCBitVector *
+_parcBitVector_LeftShiftOnce(PARCBitVector *parcBitVector)
+{
+ if (parcBitVector != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(parcBitVector, bit)) >= 0; bit++) {
+ if (bit > 0) { // The first bit falls off
+ parcBitVector_Set(parcBitVector, bit - 1);
+ }
+ parcBitVector_Clear(parcBitVector, bit);
+ }
+ }
+
+ return parcBitVector;
+}
+
+PARCBitVector *
+parcBitVector_LeftShift(PARCBitVector *parcBitVector, size_t count)
+{
+ for (int i = 0; i < count; i++) {
+ _parcBitVector_LeftShiftOnce(parcBitVector);
+ }
+
+ return parcBitVector;
+}
+
+static PARCBitVector *
+_parcBitVector_RightShiftOnce(PARCBitVector *parcBitVector)
+{
+ if (parcBitVector != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(parcBitVector, bit)) >= 0; bit++) {
+ // Shift the next sequence of one bits into the first zero bit
+ int nextZero = bit + 1;
+ while (parcBitVector_Get(parcBitVector, nextZero) == 1) {
+ nextZero++;
+ }
+ parcBitVector_Clear(parcBitVector, bit++);
+ while (bit <= nextZero) {
+ parcBitVector_Set(parcBitVector, bit);
+ bit++;
+ }
+ }
+ }
+
+ return parcBitVector;
+}
+
+PARCBitVector *
+parcBitVector_RightShift(PARCBitVector *parcBitVector, size_t count)
+{
+ for (int i = 0; i < count; i++) {
+ _parcBitVector_RightShiftOnce(parcBitVector);
+ }
+
+ return parcBitVector;
+}
diff --git a/libparc/parc/algol/parc_BitVector.h b/libparc/parc/algol/parc_BitVector.h
new file mode 100755
index 00000000..7e72ac70
--- /dev/null
+++ b/libparc/parc/algol/parc_BitVector.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_BitVector.h
+ * @ingroup types
+ *
+ */
+#ifndef libparc_parc_BitVector_h
+#define libparc_parc_BitVector_h
+
+#include <stdbool.h>
+
+/**
+ * @typedef PARCBitVector
+ * @brief A structure containing private bit vector state data variables
+ */
+struct PARCBitVector;
+typedef struct PARCBitVector PARCBitVector;
+
+/**
+ * Create a new bit vector instance.
+ *
+ * @returns NULL on error, pointer to new vector on success.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Create(void);
+
+/**
+ * Create a copy of a bit vector instance.
+ *
+ * @param [in] parcBitVector to duplicate
+ * @returns NULL on error, pointer to new copy on success.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ * assertTrue(parcBitVector_Equals(parcBitVector, copy), "Duplicate vector is unequal");
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Copy(const PARCBitVector *parcBitVector);
+
+/**
+ * Obtain a reference to a bit vector instance.
+ *
+ * @param [in] parcBitVector to obtain reference to
+ * @returns pointer to BitVector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * PARCBitVector *reference = parcBitVector_Acquire(parcBitVector);
+ * parcBitVector_Release(&reference);
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Acquire(const PARCBitVector *parcBitVector);
+
+/**
+ * Release a reference to a bit vector instance.
+ *
+ * @param [in] parcBitVector to release reference to
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * PARCBitVector *reference = parcBitVector_Acquire(parcBitVector);
+ * parcBitVector_Release(&reference);
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Release(PARCBitVector **parcBitVector);
+
+/**
+ * Determine equality of a pair of bit vectors
+ *
+ * @param [in] a bit vector to compare
+ * @param [in] b bit vector to compare
+ * @returns true if equal, false if unequal
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ * parcBitVector_Set(copy, 1);
+ * assertTrue(parcBitVector_Equals(parcBitVector, copy) == false, "Vector should have been unequal");
+ * }
+ * @endcode
+ *
+ */
+bool parcBitVector_Equals(const PARCBitVector *a, const PARCBitVector *b);
+
+
+/**
+ * Determine equality of a pair of bit vectors
+ *
+ * @param [in] parcBitVector bit vector to search
+ * @param [in] testVector bit vector to test
+ * @returns true if parcBitVector contains all bits in testVector, false otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *superSet = parcBitVector_Create();
+ * parcBitVector_Set(superSet, 10);
+ * parcBitVector_Set(superSet, 11);
+ * PARCBitVector *subSet = parcBitVector_Create();
+ * parcBitVector_Set(subSet, 10);
+ * assertTrue(parcBitVector_Contains(superSet, subSet), "Expect superSet to contain subSet");
+ * }
+ * @endcode
+ *
+ */
+bool parcBitVector_Contains(const PARCBitVector *parcBitVector, const PARCBitVector *testVector);
+
+/**
+ * Get the current value of a bit in a vector
+ *
+ * @param [in] parcBitVector to obtain value from
+ * @param [in] bit in vector to get value of
+ * @returns value of bit in vector, 1 or 0
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * }
+ * @endcode
+ *
+ */
+int parcBitVector_Get(const PARCBitVector *parcBitVector, unsigned bit);
+
+/**
+ * Set a bit in a vector
+ *
+ * @param [in] parcBitVector to set bit in
+ * @param [in] bit in vector to set
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Set(PARCBitVector *parcBitVector, unsigned bit);
+
+/**
+ * Right shift a vector contents
+ *
+ * @param [in] parcBitVector
+ * @param [in] rightShift count
+ * @param [out] input vector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 0);
+ *
+ * parcBitVector_RightShift(parcBitVector, 1);
+ * assertTrue(parcBitVector_FirstBitSet(parcBitVector) == 1,
+ * "First vector element should have moved up");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_RightShift(PARCBitVector *parcBitVector, size_t rightShift);
+
+/**
+ * Left shift a vector contents
+ *
+ * @param [in] parcBitVector
+ * @param [in] leftShift count
+ * @param [out] input vector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * parcBitVector_Set(parcBitVector, 0);
+ *
+ * parcBitVector_LeftShift(parcBitVector, 1);
+ * assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1,
+ * "First vector element should have rolled off");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_LeftShift(PARCBitVector *parcBitVector, size_t leftShift);
+
+/**
+ * Logical And of a vector contents with another vector
+ *
+ * @param [in] a vector
+ * @param [in] b vector
+ * @param [out] allocated vector with result of And operation
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *andVector = parcBitVector_Create();
+ * parcBitVector_Set(andVector, 11);
+ *
+ * PARCBitVector *result = parcBitVector_And(parcBitVector, andVector);
+ * assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "Vector should have been empty");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * parcBitVector_Release(&andVector);
+ * parcBitVector_Release(&result);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_And(const PARCBitVector *a, const PARCBitVector *b);
+
+/**
+ * Logical Or of a vector contents with another vector
+ *
+ * @param [in] a vector
+ * @param [in] b vector
+ * @param [out] allocated vector with result of Or operation
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *orVector = parcBitVector_Create();
+ * parcBitVector_Set(orVector, 11);
+ *
+ * PARCBitVector *result = parcBitVector_Or(parcBitVector, orVector);
+ * assertTrue(parcBitVector_NumberOfBitsSet(result) == 2, "Vector should have been set");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * parcBitVector_Release(&orVector);
+ * parcBitVector_Release(&result);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Or(const PARCBitVector *a, const PARCBitVector *b);
+
+/**
+ * Set a vector of bits in a vector
+ *
+ * @param [in] parcBitVector to set bits in
+ * @param [in] bitsToSet vector of bits to set
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * PARCBitVector *bitsToSet = parcBitVector_Create();
+ * parcBitVector_Set(bitsToSet, 10);
+ * parcBitVector_SetVector(parcBitVector, bitsToSet);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_SetVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToSet);
+
+/**
+ * Reset the bits of bit vector to 0
+ *
+ * @param [in] parcBitVector to set bits in
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * parcBitVector_Set(parcBitVector, 42);
+ * parcBitVector_Reset(parcBitVector);
+ * assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "Vector should have 0 bits set");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Reset(PARCBitVector *parcBitVector);
+
+/**
+ * Clear a bit in a vector
+ *
+ * @param [in] parcBitVector to clear bit in
+ * @param [in] bit in vector to clear
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * parcBitVector_Clear(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 0, "Vector should have been cleared");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Clear(PARCBitVector *parcBitVector, unsigned bit);
+
+/**
+ * Clear a vector of bits in a vector
+ *
+ * @param [in] parcBitVector to clear bits in
+ * @param [in] bitsToClear vector of bits to clear
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *bitsToClear = parcBitVector_Create();
+ * parcBitVector_Set(bitsToClear, 10);
+ * parcBitVector_SetVector(parcBitVector, bitsToClear);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 0, "Vector should have been cleared");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_ClearVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToClear);
+
+/**
+ * Return number of bits set in a vector
+ *
+ * @param [in] parcBitVector to return number of bits set from
+ * @returns number of bits currently set in bit vector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "One bit should have been set");
+ * }
+ * @endcode
+ *
+ */
+unsigned parcBitVector_NumberOfBitsSet(const PARCBitVector *parcBitVector);
+
+/**
+ * Return index if next set bit in vector
+ *
+ * @param [in] parcBitVector to inspect
+ * @param [in] startFrom bit position to start inspection from
+ * @returns index of next bit set in vector after startFrom or -1 if none
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * parcBitVector_Set(parcBitVector, 12);
+ * assertTrue(parcBitVector_NextBitSet(parcBitVector, 0) == 10, "Bit 10 should have been found first");
+ * assertTrue(parcBitVector_NextBitSet(parcBitVector, 11) == 12, "Bit 12 should have been found next");
+ * }
+ * @endcode
+ *
+ */
+unsigned parcBitVector_NextBitSet(const PARCBitVector *parcBitVector, unsigned startFrom);
+
+/**
+ * Return text representation of a bit vector
+ *
+ * @param [in] parcBitVector to represent
+ * @returns allocated character string representing bit vector which must be released by parcMemory_Deallocate
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 1);
+ * const char *bitVectorString = parcBitVector_ToString(parcBitVector);
+ * printf("Vector contents: %s\n", bitVectorString);
+ * parcMemory_Deallocate(&bitVectorString);
+ * }
+ * @endcode
+ *
+ */
+char *parcBitVector_ToString(const PARCBitVector *parcBitVector);
+#endif // libparc_parc_BitVector_h
diff --git a/libparc/parc/algol/parc_Buffer.c b/libparc/parc/algol/parc_Buffer.c
new file mode 100755
index 00000000..b2ca3577
--- /dev/null
+++ b/libparc/parc/algol/parc_Buffer.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <ctype.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_ByteArray.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct parc_buffer {
+ PARCByteArray *array;
+
+ size_t capacity;
+
+ size_t arrayOffset; // The offset within this buffer's backing PARCByteArray of the first element.
+
+ size_t position; // The index, relative to arrayOffset, of the next byte to be read from or written to this buffer.
+
+ /**
+ * The index, relative to arrayOffset, of the last position that cannot be read or written.
+ */
+ size_t limit;
+ /**
+ * A buffer's mark is the index, relative to arrayOffset, to which its position will be set when the reset function is invoked.
+ * The mark is not always defined, but when it is defined it is never negative and is never greater than the position.
+ * If the mark is defined then it is discarded when the position or the limit is adjusted to a value smaller than the mark.
+ * If the mark is not defined then invoking the reset function causes a trap.
+ */
+ size_t mark;
+};
+
+static inline void
+_discardMark(PARCBuffer *buffer)
+{
+ buffer->mark = SIZE_MAX;
+}
+
+static inline bool
+_markIsDiscarded(const PARCBuffer *buffer)
+{
+ return buffer->mark == SIZE_MAX;
+}
+
+static inline void
+_trapIfIndexExceedsLimit(const PARCBuffer *buffer, const size_t index)
+{
+ trapOutOfBoundsIf(index > buffer->limit, "PARCBuffer limit at %zd, attempted to access at %zd",
+ parcBuffer_Limit(buffer), index);
+}
+
+static inline void
+_trapIfBufferUnderflow(const PARCBuffer *buffer, const size_t requiredRemaining)
+{
+ _trapIfIndexExceedsLimit(buffer, buffer->position + requiredRemaining);
+}
+
+static inline size_t
+_effectiveIndex(const PARCBuffer *buffer, const size_t index)
+{
+ return buffer->arrayOffset + index;
+}
+
+static inline size_t
+_effectivePosition(const PARCBuffer *buffer)
+{
+ return buffer->arrayOffset + parcBuffer_Position(buffer);
+}
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define _optionalAssertInvariants(_instance_)
+#else
+# define _optionalAssertInvariants(_instance_) _assertInvariants(_instance_)
+
+static inline void
+_assertInvariants(const PARCBuffer *buffer)
+{
+ // 0 <= mark <= position <= limit <= capacity
+ assertTrue(0 <= buffer->mark,
+ "Expected 0 <= mark (%zd)", buffer->mark);
+ assertTrue(_markIsDiscarded(buffer) || buffer->mark <= buffer->position,
+ "Expected mark (%zd) <= position (%zd)", buffer->mark, buffer->position);
+ assertTrue(buffer->position <= buffer->limit,
+ "Expected position (%zd) <= limit (%zd)", buffer->position, buffer->limit);
+ assertTrue(buffer->limit <= buffer->capacity,
+ "Expected limit (%zd) <= capacity (%zd)", buffer->limit, buffer->capacity);
+ assertTrue((buffer->arrayOffset + buffer->capacity) <= parcByteArray_Capacity(buffer->array),
+ "Expected (%zd + %zd) <= %zd",
+ buffer->arrayOffset, buffer->capacity, parcByteArray_Capacity(buffer->array));
+}
+#endif
+
+static inline int
+_digittoint(char digit)
+{
+ int result = -1;
+
+ int value = digit - '0';
+
+ if ((unsigned) value < 10) {
+ result = value;
+ } else {
+ value = digit - 'a';
+ if ((unsigned) value < 6) {
+ result = value + 10;
+ } else {
+ value = digit - 'A';
+ if ((unsigned) value < 6) {
+ result = value + 10;
+ }
+ }
+ }
+
+ return result;
+}
+
+// This hexadecimal parsing code needs to be fixed - see FogBugz:3598
+
+static char *_hexDigitsUpper = "0123456789ABCDEF";
+static char *_hexDigitsLower = "0123456789abcdef";
+
+static inline char
+_fromHexDigit(char hexDigit)
+{
+ for (char i = 0; i < 16; i++) {
+ if (hexDigit == _hexDigitsLower[(int) i] || hexDigit == _hexDigitsUpper[(int) i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static inline uint8_t
+_hexByte(const char *hexByte)
+{
+ uint8_t result = (uint8_t) (_fromHexDigit(hexByte[0]) << 4) | _fromHexDigit(hexByte[1]);
+ return result;
+}
+
+static inline char *
+_parcBuffer_CheckValidity(const PARCBuffer *buffer)
+{
+ char *result = NULL;
+
+ if (buffer != NULL) {
+ if (parcObject_IsValid(buffer)) {
+ if (parcByteArray_IsValid(buffer->array)) {
+ // 0 <= mark <= position <= limit <= capacity
+ if (_markIsDiscarded(buffer) || buffer->mark <= buffer->position) {
+ if (buffer->position <= buffer->limit) {
+ if (buffer->limit <= buffer->capacity) {
+ if ((buffer->arrayOffset + buffer->capacity) <= parcByteArray_Capacity(buffer->array)) {
+ result = NULL;
+ } else {
+ result = "PARCBuffer offset+capacity exceeds the capacity of the underlying PARCByteArray";
+ }
+ } else {
+ result = "PARCBuffer limit exceeds the capacity.";
+ }
+ } else {
+ result = "PARCBuffer position exceeds the limit.";
+ }
+ } else {
+ result = "PARCBuffer mark exceeds the current position";
+ }
+ } else {
+ result = "PARCBuffer underlying PARCByteArray is invalid";
+ }
+ } else {
+ result = "PARCBuffer is an invalid PARCObject.";
+ }
+ } else {
+ result = "PARCBuffer is NULL";
+ }
+
+ return result;
+}
+
+void
+parcBuffer_AssertValid(const PARCBuffer *buffer)
+{
+ char *explanation = _parcBuffer_CheckValidity(buffer);
+
+ trapIllegalValueIf(explanation != NULL, "PARCBuffer@%p %s.", (void *) buffer, explanation);
+}
+
+bool
+parcBuffer_IsValid(const PARCBuffer *buffer)
+{
+ bool result = false;
+
+ if (buffer != NULL) {
+ if (parcObject_IsValid(buffer)) {
+ if (parcByteArray_IsValid(buffer->array)) {
+ // 0 <= mark <= position <= limit <= capacity
+ if (_markIsDiscarded(buffer) || buffer->mark <= buffer->position) {
+ if (buffer->position <= buffer->limit) {
+ if (buffer->limit <= buffer->capacity) {
+ if ((buffer->arrayOffset + buffer->capacity) <= parcByteArray_Capacity(buffer->array)) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static bool
+_parcBuffer_Destructor(PARCBuffer **bufferPtr)
+{
+ PARCBuffer *buffer = *bufferPtr;
+
+ parcByteArray_Release(&buffer->array);
+ return true;
+}
+
+parcObject_Override(PARCBuffer, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcBuffer_Destructor,
+ .copy = (PARCObjectCopy *) parcBuffer_Copy,
+ .toString = (PARCObjectToString *) parcBuffer_ToString,
+ .equals = (PARCObjectEquals *) parcBuffer_Equals,
+ .compare = (PARCObjectCompare *) parcBuffer_Compare,
+ .hashCode = (PARCObjectHashCode *) parcBuffer_HashCode,
+ .display = (PARCObjectDisplay *) parcBuffer_Display);
+
+/**
+ * Initialise a parcBuffer instance.
+ *
+ * The buffer's offset, position, limit and capacity are set to the given values.
+ * The mark is made invalid.
+ *
+ * @return The same pointer as `result`.
+ */
+static PARCBuffer *
+_parcBuffer_Init(PARCBuffer *result, PARCByteArray *array, size_t offset, size_t position, size_t limit, size_t capacity)
+{
+ result->array = array;
+ result->arrayOffset = offset;
+ result->position = position;
+ result->limit = limit;
+ result->capacity = capacity;
+ _discardMark(result);
+
+ parcBuffer_OptionalAssertValid(result);
+
+ return result;
+}
+
+static inline PARCBuffer *
+_parcBuffer_getInstance(void)
+{
+ PARCBuffer *result = parcObject_CreateInstance(PARCBuffer);
+
+ return result;
+}
+
+static inline size_t
+_computeNewLimit(size_t oldCapacity, size_t oldLimit, size_t newCapacity)
+{
+ size_t result = newCapacity;
+
+ bool limitIsAtCapacity = (oldLimit == oldCapacity);
+
+ if (newCapacity > oldCapacity) {
+ if (limitIsAtCapacity) {
+ result = newCapacity;
+ } else {
+ result = oldLimit;
+ }
+ } else {
+ if (limitIsAtCapacity) {
+ result = newCapacity;
+ } else {
+ result = (oldLimit < newCapacity) ? oldLimit : newCapacity;
+ }
+ }
+
+ return result;
+}
+
+static inline size_t
+_computeNewMark(size_t oldMark, size_t newLimit, size_t newCapacity)
+{
+ size_t result = oldMark;
+
+ if (oldMark != SIZE_MAX) {
+ if (oldMark > newCapacity) {
+ result = SIZE_MAX;
+ } else {
+ result = oldMark;
+ }
+
+ if (result > newLimit) {
+ result = SIZE_MAX;
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_WrapByteArray(PARCByteArray *byteArray, size_t position, size_t limit)
+{
+ PARCBuffer *result = NULL;
+
+ // The limit cannot exceed the capacity of the PARCByteArray.
+ if (limit > parcByteArray_Capacity(byteArray)) {
+ return NULL;
+ }
+ if (byteArray != NULL) {
+ result = _parcBuffer_getInstance();
+
+ if (result != NULL) {
+ return _parcBuffer_Init(result,
+ parcByteArray_Acquire(byteArray),
+ 0, position, limit,
+ parcByteArray_Capacity(byteArray));
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_Resize(PARCBuffer *buffer, size_t newCapacity)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ PARCByteArray *newArray = parcByteArray_Allocate(newCapacity);
+ if (newArray == NULL) {
+ return NULL;
+ }
+
+ size_t numberOfBytesToCopy = parcBuffer_Capacity(buffer);
+ if (numberOfBytesToCopy > newCapacity) {
+ numberOfBytesToCopy = newCapacity;
+ }
+
+ parcByteArray_PutBytes(newArray, 0, numberOfBytesToCopy, &parcByteArray_Array(buffer->array)[buffer->arrayOffset]);
+
+ parcByteArray_Release(&buffer->array);
+
+ buffer->array = newArray;
+ buffer->arrayOffset = 0;
+ buffer->limit = _computeNewLimit(buffer->capacity, buffer->limit, newCapacity);
+ buffer->mark = _computeNewMark(buffer->mark, buffer->limit, newCapacity);
+ buffer->capacity = newCapacity;
+ buffer->position = (buffer->position < buffer->limit) ? buffer->position : buffer->limit;
+
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_Allocate(size_t capacity)
+{
+ PARCByteArray *array = parcByteArray_Allocate(capacity);
+
+ if (array != NULL) {
+ PARCBuffer *result = _parcBuffer_getInstance();
+ if (result != NULL) {
+ return _parcBuffer_Init(result, array, 0, 0, capacity, capacity);
+ }
+ parcByteArray_Release(&array);
+ }
+
+ return NULL;
+}
+
+PARCBuffer *
+parcBuffer_Wrap(void *array, size_t arrayLength, size_t position, size_t limit)
+{
+ PARCBuffer *result = NULL;
+
+ if (array != NULL) {
+ PARCByteArray *byteArray = parcByteArray_Wrap(arrayLength, array);
+
+ if (byteArray != NULL) {
+ result = parcBuffer_WrapByteArray(byteArray, position, limit);
+ parcByteArray_Release(&byteArray);
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_WrapCString(char *string)
+{
+ size_t length = strlen(string);
+ return parcBuffer_Wrap(string, length, 0, length);
+}
+
+PARCBuffer *
+parcBuffer_AllocateCString(const char *string)
+{
+ size_t length = strlen(string);
+ PARCBuffer *buffer = parcBuffer_Allocate(length + 1);
+ parcBuffer_PutArray(buffer, length, (const uint8_t *) string);
+ parcBuffer_PutUint8(buffer, 0);
+ parcBuffer_SetPosition(buffer, buffer->position - 1);
+ parcBuffer_Flip(buffer);
+
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_ParseHexString(const char *hexString)
+{
+ size_t length = strlen(hexString);
+
+ // The hex string must be an even length greater than zero.
+ if (length > 0 && (length % 2) == 1) {
+ return NULL;
+ }
+
+ PARCBuffer *result = parcBuffer_Allocate(length);
+ for (size_t i = 0; i < length; i += 2) {
+ parcBuffer_PutUint8(result, _hexByte(&hexString[i]));
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_CreateFromArray(const void *bytes, const size_t length)
+{
+ assertTrue(length == 0 || bytes != NULL,
+ "If the byte array is NULL, then length MUST be zero.");
+
+ PARCBuffer *result = parcBuffer_Allocate(length);
+ parcBuffer_PutArray(result, length, bytes);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcBuffer, PARCBuffer);
+
+parcObject_ImplementRelease(parcBuffer, PARCBuffer);
+
+size_t
+parcBuffer_Capacity(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->capacity;
+}
+
+PARCBuffer *
+parcBuffer_Clear(PARCBuffer *buffer)
+{
+ parcBuffer_SetPosition(buffer, 0);
+ parcBuffer_SetLimit(buffer, parcBuffer_Capacity(buffer));
+ _discardMark(buffer);
+ return buffer;
+}
+
+bool
+parcBuffer_Equals(const PARCBuffer *x, const PARCBuffer *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ return (parcBuffer_Compare(x, y) == 0);
+}
+
+int
+parcBuffer_Compare(const PARCBuffer *x, const PARCBuffer *y)
+{
+ if (x == y) {
+ return 0;
+ }
+
+ if (x == NULL) {
+ return -1;
+ }
+
+ if (y == NULL) {
+ return +1;
+ }
+
+ size_t count = parcBuffer_Remaining(x);
+ if (count > parcBuffer_Remaining(y)) {
+ count = parcBuffer_Remaining(y);
+ }
+
+ int result = 0;
+
+ if (count > 0) {
+ result = memcmp(parcBuffer_Overlay((PARCBuffer *) x, 0), parcBuffer_Overlay((PARCBuffer *) y, 0), count);
+ }
+
+ if (result == 0) {
+ // This is when one buffer is longer than the other, and they are equivalent thus far.
+ ssize_t difference = parcBuffer_Remaining(x) - parcBuffer_Remaining(y);
+ if (difference > 0) {
+ result = +1;
+ } else if (difference < 0) {
+ result = -1;
+ }
+ }
+
+ return result;
+}
+
+PARCByteArray *
+parcBuffer_Array(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->array;
+}
+
+PARCBuffer *
+parcBuffer_Duplicate(const PARCBuffer *original)
+{
+ PARCBuffer *result = _parcBuffer_getInstance();
+ if (result != NULL) {
+ _parcBuffer_Init(result,
+ parcByteArray_Acquire(original->array),
+ original->arrayOffset,
+ original->position,
+ parcBuffer_Limit(original),
+ original->capacity);
+
+ _optionalAssertInvariants(result);
+ }
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_Slice(const PARCBuffer *original)
+{
+ PARCBuffer *result = _parcBuffer_getInstance();
+ if (result != NULL) {
+ _parcBuffer_Init(result,
+ parcByteArray_Acquire(original->array),
+ original->arrayOffset + parcBuffer_Position(original),
+ 0,
+ parcBuffer_Limit(original) - parcBuffer_Position(original),
+ parcBuffer_Limit(original) - parcBuffer_Position(original));
+
+ _optionalAssertInvariants(result);
+ }
+ return result;
+}
+
+size_t
+parcBuffer_ArrayOffset(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->arrayOffset;
+}
+
+PARCBuffer *
+parcBuffer_Reset(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ assertFalse(_markIsDiscarded(buffer),
+ "The mark has not been set");
+ buffer->position = buffer->mark;
+
+ _optionalAssertInvariants(buffer);
+
+ return buffer;
+}
+
+size_t
+parcBuffer_Limit(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->limit;
+}
+
+PARCBuffer *
+parcBuffer_Mark(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ buffer->mark = buffer->position;
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_SetLimit(PARCBuffer *buffer, size_t newLimit)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(newLimit <= parcBuffer_Capacity(buffer),
+ "new limit cannot be larger than the capacity");
+
+ if (_markIsDiscarded(buffer)) {
+ buffer->limit = newLimit;
+ _discardMark(buffer);
+ } else {
+ if (newLimit < buffer->position) {
+ buffer->position = newLimit;
+ }
+ if (newLimit < buffer->mark) {
+ _discardMark(buffer);
+ }
+ buffer->limit = newLimit;
+ }
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+size_t
+parcBuffer_Position(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->position;
+}
+
+size_t
+parcBuffer_Remaining(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->limit - buffer->position;
+}
+
+bool
+parcBuffer_HasRemaining(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return parcBuffer_Remaining(buffer) != 0;
+}
+
+PARCBuffer *
+parcBuffer_SetPosition(PARCBuffer *buffer, size_t newPosition)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ assertFalse(newPosition > buffer->limit,
+ "new position cannot be greater the buffer's limit");
+
+ buffer->position = newPosition;
+ if (!_markIsDiscarded(buffer) && newPosition < buffer->mark) {
+ _discardMark(buffer);
+ }
+
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_Rewind(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ buffer->position = 0;
+ _discardMark(buffer);
+
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_Copy(const PARCBuffer *original)
+{
+ parcBuffer_OptionalAssertValid(original);
+
+ PARCBuffer *result = _parcBuffer_getInstance();
+
+ if (result != NULL) {
+ PARCByteArray *array = parcByteArray_Copy(original->array);
+ if (array != NULL) {
+ _parcBuffer_Init(result,
+ array,
+ parcBuffer_ArrayOffset(original),
+ parcBuffer_Position(original),
+ parcBuffer_Limit(original),
+ parcBuffer_Capacity(original));
+ } else {
+ parcBuffer_Release(&result);
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_Flip(PARCBuffer *result)
+{
+ parcBuffer_OptionalAssertValid(result);
+
+ size_t position = result->position;
+ result->position = 0;
+ result->limit = position;
+
+ _optionalAssertInvariants(result);
+
+ return result;
+}
+
+uint8_t
+parcBuffer_GetAtIndex(const PARCBuffer *buffer, size_t index)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ _trapIfIndexExceedsLimit(buffer, index);
+
+ return parcByteArray_GetByte(buffer->array, _effectiveIndex(buffer, index));
+}
+
+void *
+parcBuffer_Overlay(PARCBuffer *buffer, size_t length)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ _trapIfBufferUnderflow(buffer, length);
+
+ uint8_t *result = parcByteArray_AddressOfIndex(buffer->array, _effectiveIndex(buffer, parcBuffer_Position(buffer)));
+ buffer->position += length;
+ return result;
+}
+
+uint8_t
+parcBuffer_GetUint8(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ _trapIfBufferUnderflow(buffer, 1);
+
+ uint8_t result = parcByteArray_GetByte(buffer->array, _effectivePosition(buffer));
+ buffer->position++;
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_GetBytes(PARCBuffer *buffer, size_t length, uint8_t array[length])
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ _trapIfBufferUnderflow(buffer, length);
+
+ parcByteArray_GetBytes(buffer->array, _effectivePosition(buffer), length, array);
+ buffer->position += length;
+
+ return buffer;
+}
+
+uint16_t
+parcBuffer_GetUint16(PARCBuffer *buffer)
+{
+ uint8_t high = parcBuffer_GetUint8(buffer);
+ uint8_t low = parcBuffer_GetUint8(buffer);
+
+ uint16_t result = (high << 8) | low;
+
+ return result;
+}
+
+uint32_t
+parcBuffer_GetUint32(PARCBuffer *buffer)
+{
+ uint32_t result = 0;
+ for (int i = 0; i < sizeof(uint32_t); i++) {
+ result = result << 8 | parcBuffer_GetUint8(buffer);
+ }
+ return result;
+}
+
+uint64_t
+parcBuffer_GetUint64(PARCBuffer *buffer)
+{
+ uint64_t result = 0;
+ for (int i = 0; i < sizeof(uint64_t); i++) {
+ result = result << 8 | parcBuffer_GetUint8(buffer);
+ }
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_PutUint8(PARCBuffer *buffer, uint8_t value)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(parcBuffer_Remaining(buffer) >= 1,
+ "Buffer overflow");
+
+ parcByteArray_PutByte(buffer->array, _effectivePosition(buffer), value);
+ buffer->position++;
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutUint16(PARCBuffer *buffer, uint16_t value)
+{
+ assertTrue(parcBuffer_Remaining(buffer) >= sizeof(uint16_t),
+ "Buffer overflow");
+
+ parcBuffer_PutUint8(buffer, (value >> 8) & 0xFF);
+ parcBuffer_PutUint8(buffer, value & 0xFF);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutUint32(PARCBuffer *buffer, uint32_t value)
+{
+ assertTrue(parcBuffer_Remaining(buffer) >= sizeof(uint32_t),
+ "Buffer overflow");
+ for (int i = sizeof(uint32_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ parcBuffer_PutUint8(buffer, b);
+ }
+ parcBuffer_PutUint8(buffer, value & 0xFF);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutUint64(PARCBuffer *buffer, uint64_t value)
+{
+ assertTrue(parcBuffer_Remaining(buffer) >= sizeof(uint64_t),
+ "Buffer overflow");
+ for (int i = sizeof(uint64_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ parcBuffer_PutUint8(buffer, b);
+ }
+ parcBuffer_PutUint8(buffer, value & 0xFF);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutAtIndex(PARCBuffer *buffer, size_t index, uint8_t value)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(_effectiveIndex(buffer, index) < parcBuffer_Limit(buffer), "Buffer overflow");
+
+ parcByteArray_PutByte(buffer->array, _effectiveIndex(buffer, index), value);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutArray(PARCBuffer *buffer, size_t arrayLength, const uint8_t array[arrayLength])
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(parcBuffer_Remaining(buffer) >= arrayLength,
+ "Buffer overflow");
+
+ parcByteArray_PutBytes(buffer->array, _effectivePosition(buffer), arrayLength, array);
+ return parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + arrayLength);
+}
+
+PARCBuffer *
+parcBuffer_PutCString(PARCBuffer *buffer, const char *string)
+{
+ return parcBuffer_PutArray(buffer, strlen(string) + 1, (const uint8_t *) string);
+}
+
+PARCBuffer *
+parcBuffer_PutBuffer(PARCBuffer *result, const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(parcBuffer_Remaining(result) >= parcBuffer_Remaining(buffer),
+ "Buffer overflow. %zd bytes remaining, %zd required.", parcBuffer_Remaining(result), parcBuffer_Remaining(buffer));
+
+ size_t length = parcBuffer_Remaining(buffer);
+ parcByteArray_ArrayCopy(result->array, _effectivePosition(result), buffer->array, _effectivePosition(buffer), length);
+ parcBuffer_SetPosition(result, parcBuffer_Position(result) + length);
+ return result;
+}
+
+PARCHashCode
+parcBuffer_HashCode(const PARCBuffer *buffer)
+{
+ PARCHashCode result = 0;
+
+ size_t remaining = parcBuffer_Remaining(buffer);
+ if (remaining > 0) {
+ result = parcHashCode_Hash(parcBuffer_Overlay((PARCBuffer *) buffer, 0), parcBuffer_Remaining(buffer));
+ }
+ return result;
+}
+
+size_t
+parcBuffer_FindUint8(const PARCBuffer *buffer, uint8_t byte)
+{
+ for (size_t i = parcBuffer_Position(buffer); i < parcBuffer_Limit(buffer); i++) {
+ if (parcBuffer_GetAtIndex(buffer, i) == byte) {
+ return i;
+ }
+ }
+ return SIZE_MAX;
+}
+
+char *
+parcBuffer_ToString(const PARCBuffer *buffer)
+{
+ size_t remaining = parcBuffer_Remaining(buffer);
+
+ char *result = parcMemory_Allocate(remaining + 1);
+ if (remaining > 0) {
+ assertNotNull(result, "parcMemory_Allocate returned NULL");
+ if (result != NULL) {
+ memcpy(result, parcBuffer_Overlay((PARCBuffer *) buffer, 0), remaining);
+ }
+ }
+ result[remaining] = 0;
+ return result;
+}
+
+void
+parcBuffer_Display(const PARCBuffer *buffer, int indentation)
+{
+ if (buffer == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCBuffer@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCBuffer@%p {", (void *) buffer);
+ parcDisplayIndented_PrintLine(indentation + 1,
+ ".arrayOffset=%zd .position=%zd .limit=%zd .mark=%zd",
+ buffer->arrayOffset, buffer->position, buffer->limit, buffer->mark);
+ parcByteArray_Display(buffer->array, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+ }
+}
+
+// Given a value, return the low nibble as a hex character.
+static char
+_toHexDigit(const char value)
+{
+ return "0123456789ABCDEF"[value & 0xF];
+}
+
+char *
+parcBuffer_ToHexString(const PARCBuffer *buffer)
+{
+ if (buffer == NULL) {
+ return parcMemory_StringDuplicate("null", 4);
+ }
+
+ size_t length = parcBuffer_Remaining(buffer);
+ // Hopefully length is less than (2^(sizeof(size_t)*8) / 2)
+
+ char *result = parcMemory_AllocateAndClear((length * 2) + 1);
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", (length * 2) + 1);
+
+ for (size_t i = 0; i < length; i++) {
+ unsigned char byte = parcBuffer_GetAtIndex(buffer, i);
+ result[i * 2] = _toHexDigit(byte >> 4);
+ result[i * 2 + 1] = _toHexDigit(byte);
+ }
+ result[length * 2] = 0;
+
+ return result;
+}
+
+bool
+parcBuffer_SkipOver(PARCBuffer *buffer, size_t length, const uint8_t bytesToSkipOver[length])
+{
+ while (parcBuffer_Remaining(buffer) > 0) {
+ uint8_t character = parcBuffer_GetUint8(buffer);
+ if (memchr(bytesToSkipOver, character, length) == NULL) {
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) - 1);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+parcBuffer_SkipTo(PARCBuffer *buffer, size_t length, const uint8_t bytesToSkipTo[length])
+{
+ bool result = false;
+
+ while (parcBuffer_Remaining(buffer) > 0) {
+ uint8_t character = parcBuffer_GetUint8(buffer);
+ if (memchr(bytesToSkipTo, character, length) != NULL) {
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) - 1);
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
+uint8_t
+parcBuffer_PeekByte(const PARCBuffer *buffer)
+{
+ return parcBuffer_GetAtIndex(buffer, parcBuffer_Position(buffer));
+}
+
+uint64_t
+parcBuffer_ParseHexNumber(PARCBuffer *buffer)
+{
+ char *bytes = parcBuffer_Overlay(buffer, 0);
+
+ int start = 0;
+ if (parcBuffer_Remaining(buffer) > 2) {
+ if (bytes[0] == '0' && bytes[1] == 'x') {
+ start = 2;
+ }
+ }
+
+ unsigned count = 0;
+ uint64_t result = 0;
+ for (int i = start; i < parcBuffer_Remaining(buffer) && isxdigit(bytes[i]); i++) {
+ result = (result * 16) + _digittoint(bytes[i]);
+ count++;
+ }
+
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + start + count);
+
+ return result;
+}
+
+uint64_t
+parcBuffer_ParseDecimalNumber(PARCBuffer *buffer)
+{
+ char *bytes = parcBuffer_Overlay(buffer, 0);
+
+ int start = 0;
+
+ unsigned count = 0;
+ uint64_t result = 0;
+ for (int i = start; i < parcBuffer_Remaining(buffer) && isdigit(bytes[i]); i++) {
+ result = (result * 10) + _digittoint(bytes[i]);
+ count++;
+ }
+
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + count);
+
+ return result;
+}
+
+uint64_t
+parcBuffer_ParseNumeric(PARCBuffer *buffer)
+{
+ uint64_t result = 0;
+
+ char *bytes = parcBuffer_Overlay(buffer, 0);
+
+ if (parcBuffer_Remaining(buffer) > 2 && bytes[0] == '0' && bytes[1] == 'x') {
+ result = parcBuffer_ParseHexNumber(buffer);
+ } else {
+ result = parcBuffer_ParseDecimalNumber(buffer);
+ }
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_Buffer.h b/libparc/parc/algol/parc_Buffer.h
new file mode 100644
index 00000000..2c7f56fd
--- /dev/null
+++ b/libparc/parc/algol/parc_Buffer.h
@@ -0,0 +1,1665 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Buffer.h
+ * @ingroup memory
+ * @brief An indexable, linear buffer of bytes.
+ *
+ * A `PARCBuffer` is a linear, finite sequence of bytes.
+ * The essential properties of a buffer are its content, its capacity, limit, and position:
+ *
+ * @htmlonly
+ * <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1" viewBox="48 143 304 126" width="304pt" height="126pt">
+ * <defs>
+ * <font-face font-family="Helvetica Neue" font-size="10" panose-1="2 0 5 3 0 0 0 2 0 4" units-per-em="1000" underline-position="-100" underline-thickness="50" slope="0" x-height="517" cap-height="714" ascent="951.99585" descent="-212.99744" font-weight="500">
+ * <font-face-src>
+ * <font-face-name name="HelveticaNeue"/>
+ * </font-face-src>
+ * </font-face>
+ * <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black">
+ * <g>
+ * <path d="M 8 0 L 0 -3 L 0 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+ * </g>
+ * </marker>
+ * </defs>
+ * <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+ * <title>icon_512x512</title>
+ * <rect fill="white" width="512" height="512"/>
+ * <g>
+ * <title>Layer 1</title>
+ * <text transform="translate(73 231.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".055" y="10" textLength="13.37">Off</tspan>
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x="13.425" y="10" textLength="13.52">set</tspan>
+ * </text>
+ * <text transform="translate(178.5 231)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".445" y="10" textLength="36.11">Position</tspan>
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x="7.2" y="22" textLength="22.6">Mark</tspan>
+ * </text>
+ * <text transform="translate(294 231.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".16" y="10" textLength="21.68">Limit</tspan>
+ * </text>
+ * <text transform="translate(271 157.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".185" y="10" textLength="39.63">Capacity</tspan>
+ * </text>
+ * <text transform="translate(83 157.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".245" y="10" textLength="23.51">Array</tspan>
+ * </text>
+ * <path d="M 78 165.48333 C 73.6671 165.98884 67.757544 163.49623 65 167 C 63.49089 168.91749 62.925312 172.63153 62.52875 176.66717" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <rect x="59" y="187" width="281" height="13" fill="#205469"/>
+ * <rect x="59" y="187" width="281" height="13" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 316 166.11628 C 321.9994 166.74412 330.42197 164.60163 334 168 C 335.8631 169.76954 336.41326 173.04195 336.67595 176.64326" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <rect x="116" y="181" width="160" height="27" fill="#f60"/>
+ * <rect x="116" y="181" width="160" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 105 234.05085 C 108.6663 233.3673 114.16685 236.34137 116 232 C 117.15073 229.27477 116.856755 223.66586 116.47841 217.88884" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 289 235.56897 C 284.6671 235.04603 278.16645 238.59437 276 234 C 274.57827 230.98495 275.02256 224.46193 275.496 217.88448" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <line x1="173.5" y1="232.84568" x2="125.08789" y2="211.92687" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <line x1="220.5" y1="232.58861" x2="266.94855" y2="212.01014" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * </g>
+ * </g>
+ * </svg>
+ * @endhtmlonly
+ *
+ * * A buffer's capacity is the number of bytes it contains.
+ * The capacity of a buffer is never negative and never changes.
+ *
+ * * A buffer's limit is the index of the first byte that should not be read or written.
+ * A buffer's limit is never negative and is never greater than its capacity.
+ *
+ * * A buffer's position is a cursor to or index of the next byte to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * A PARCBuffer's capacity may be larger than the extent of data manipulated by the buffer.
+ * The extent of the data manipulated by the buffer is manipulated via:
+ * * {@link parcBuffer_Position},
+ * * {@link parcBuffer_SetPosition},
+ * * {@link parcBuffer_Limit},
+ * * {@link parcBuffer_SetLimit} and
+ * * {@link parcBuffer_Flip}.
+ *
+ * Strictly speaking, these relations are always true: _0 <= mark <= position <= limit <= capacity_
+ *
+ * The general model for use is to:
+ * * Create a buffer using a form of {@link parcBuffer_Allocate} or {@link parcBuffer_Wrap}.
+ * * Optionally insert data into the buffer via put operations,
+ * ultimately setting the position at the end of the valid data.
+ * * 'Flip' the buffer using the {@link parcBuffer_Flip} function to set the position to 0 and the limit at the end
+ * of the valid data.
+ * * Optionally get data from the buffer via one of the many get operations.
+ * * Use {@link parcBuffer_Rewind} function to set the position to 0 again, leaving the limit at the end of the valid data.
+ *
+ * Data is placed into a `PARCBuffer` via `Put` functions, and retreived from the buffer via `Get` operations.
+ * Both `Put` and `Get` perform their operations at the position of the buffer and update the position to the location of the
+ * next element of data.
+ * Both `Put` and `Get` operations have a full compliment of intrinsic data types that operate on data at
+ * relative positions in the buffer.
+ *
+ * The function {@link parcBuffer_GetAtIndex} provides absolute index access to the buffer for bytes.
+ *
+ * * {@link parcBuffer_PutUint8},
+ * * {@link parcBuffer_PutUint16},
+ * * {@link parcBuffer_PutUint32},
+ * * {@link parcBuffer_PutUint64},
+ * * {@link parcBuffer_PutAtIndex}
+ *
+ * * {@link parcBuffer_GetUint8},
+ * * {@link parcBuffer_GetUint16},
+ * * {@link parcBuffer_GetUint32},
+ * * {@link parcBuffer_GetUint64},
+ * * {@link parcBuffer_GetAtIndex}
+ *
+ */
+#ifndef libparc_parc_Buffer_h
+#define libparc_parc_Buffer_h
+
+typedef struct parc_buffer PARCBuffer;
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_ByteArray.h>
+
+extern parcObjectDescriptor_Declaration(PARCBuffer);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcBuffer_OptionalAssertValid(_instance_)
+#else
+# define parcBuffer_OptionalAssertValid(_instance_) parcBuffer_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `PARCBuffer` is valid.
+ *
+ * If the instance is not valid, terminate via `trapIllegalValue()`
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(64);
+ *
+ * parcBuffer_AssertValid(array);
+ * }
+ * @endcode
+ * @see parcBuffer_OptionalAssertValid
+ */
+void parcBuffer_AssertValid(const PARCBuffer *instance);
+
+/**
+ * Determine if an instance of `PARCBuffer` is valid.
+ *
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(64);
+ *
+ * if (parcBuffer_IsValid(buffer)) {
+ * printf("Buffer is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcBuffer_IsValid(const PARCBuffer *buffer);
+
+/**
+ * Create a new instance of `PARCBuffer` using dynamically allocated memory.
+ *
+ * The new buffer's position will be zero,
+ * its limit will be set to `length`,
+ * its mark will be undefined,
+ * and each of its elements will be initialized to zero.
+ *
+ * If capacity is zero, the buffer contains no underlying byte array.
+ *
+ * @param [in] capacity The number of bytes to allocate.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(64);
+ *
+ * parcBuffer_Release(&&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Allocate(size_t capacity);
+
+/**
+ * Create a new instance of `PARCBuffer` using using program supplied static memory (rather than allocated).
+ *
+ * The new buffer will be backed by the given array, @p array.
+ * Modifications to the buffer will cause the array to be modified and vice versa.
+ *
+ * The new buffer's capacity will be @p arrayLength,
+ * its initial position will be @p position ,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * In all cases, _0 <= position <= limit <= capacity_
+ *
+ * Its backing array will be the given array, starting at index 0 of that array.
+ *
+ * @param [in] array A pointer to a memory array.
+ * @param [in] arrayLength The length, in `uint8_t` units, of the memory array.
+ * @param [in] position The initial value for the buffer's position.
+ * @param [in] limit The initial value for the buffer's limit.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[64];
+ *
+ * PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Release
+ */
+PARCBuffer *parcBuffer_Wrap(void *array, size_t arrayLength, size_t position, size_t limit);
+
+/**
+ * Create a new instance of `PARCBuffer` using referencing the given {@link PARCByteArray}.
+ *
+ * A reference to the `PARCByteArray` is acquired.
+ *
+ * The new buffer will be backed by the given `PARCByteArray`.
+ * Modifications to the buffer will cause the array to be modified and vice versa.
+ *
+ * The new buffer's capacity will be @p arrayLength,
+ * its initial position will be @p position ,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * In all cases, _0 <= position <= limit <= capacity_
+ *
+ * The new buffer's
+ * capacity will be the length of the `PARCByteArray`,
+ * its initial position will be @p position ,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * @param [in] byteArray A pointer to a `PARCByteArray` instance.
+ * @param [in] position The initial value for the buffer's position.
+ * @param [in] limit The initial value for the buffer's limit which must be less than or equal to the PARCByteArray's capacity.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *array = parcByteArray_Allocate(64);
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapByteArray(array, 0, parcByteArray_Capacity(array));
+ *
+ * parcBuffer_Release(&&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Wrap
+ */
+PARCBuffer *parcBuffer_WrapByteArray(PARCByteArray *byteArray, size_t position, size_t limit);
+
+/**
+ * Create a new instance of `PARCBuffer` wrapping the given null-terminated C string as its value.
+ *
+ * The new buffer's capacity will be the length of the string excluding the terminating nul character.
+ * its initial position will be 0,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * @param [in] string A pointer to a C-string to copy and then wrap.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Wrap
+ */
+PARCBuffer *parcBuffer_WrapCString(char *string);
+
+/**
+ * Create a new instance of a `PARCBuffer` copying the given null-terminated C string as its value.
+ *
+ * The new buffer's capacity will be the length of the string excluding the terminating nul character.
+ * its initial position will be 0,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * @param [in] string A pointer to C-string to copy and then wrap.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *buffer = parcBuffer_AllocateCString("test string");
+ *
+ * parcBUffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_AllocateCString(const char *string);
+
+/**
+ * Create a `PARCBuffer` initalised with a copy of the contents of given byte array.
+ *
+ * The length must be non-negative (> 0) and the array pointer must not be NULL.
+ * The contents of the given array are used to initialize the `PARCBuffer` instance,
+ * and the size of the new instance is equal to the specified length (just wide enough to fit the array).
+ *
+ * @param [in] bytes A pointer to an array of bytes.
+ * @param [in] length The number of bytes to copy to the `PARCBuffer`.
+ *
+ * @return A newly allocated `PARCBuffer` instance that must be freed via `parcBuffer_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * unsigned char array[] = { 1, 2, 3, 4, 5 };
+ * PARCBuffer *buffer = parcBuffer_CreateFromArray(array, sizeof(array));
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_CreateFromArray(const void *bytes, size_t length);
+
+/**
+ * Parse a null-terminated hexadecimal string to create a new `PARCBuffer` instance.
+ *
+ * The hex string must be null-terminated so parsing is deterministic and correct.
+ * The hex string parameter is not modified in any way.
+ * The hex string must be an even length greater than zero.
+ *
+ * @param [in] hexString The hex string to parse.
+ *
+ * @return NULL The string could not be parsed
+ * @return A new `PARCElasticBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * char *expected = "0123456789ABCDEF";
+ * PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_ParseHexString(expected));
+ * printf("String: %s\n", parcBuffer_ToString(buffer));
+ *
+ * parcBuffer_Release(buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_ParseHexString(const char *hexString);
+
+/**
+ * Increase or decrease the capacity of an existing PARCBuffer.
+ *
+ * If the new capacity is greater than the old capacity and the limit is currently set to the old capacity,
+ * then set the new limit to the new capacity.
+ * Otherwise, if the limit is not currently set to the capacity, then leave the limit unchanged.
+ *
+ * If the new capacity is less than the old capacity and the limit is currently set to the old capacity,
+ * then set the new limit to the new capacity.
+ * Otherwise, set the limit to the the lesser of the old limit or the new capacity.
+ * If the limit is not currently set to the capacity,
+ * the set the limit to the the lesser of the old limit or the new capacity.
+ *
+ * If the original mark exceeds the new limit, the new mark is invalidated and any subsequent
+ * operation on the resulting `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * If the original position of the buffer is beyond the new limit of the buffer, the position is set to the new limit.
+ *
+ * The contents of the old buffer are preserved from the origin to the new limit.
+ *
+ * This operation may induce a memory copy.
+ * As a consequence, any `PARCBuffer` instances previously created via {@link parcBuffer_Slice}
+ * refer to memory previously used by this `PARCBuffer`.
+ *
+ * A PARCBuffer originally created via any of the `parcBuffer_Wrap` forms,
+ * may no longer refer to the original wrapped data.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ * @param [in] capacity The new capacity of `PARCBuffer`
+ *
+ * @return PARCBuffer A new `PARCBuffer` instance initialized with the contents of the given buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcBuffer_Resize(buffer, 4);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Wrap
+ */
+PARCBuffer *parcBuffer_Resize(PARCBuffer *buffer, size_t capacity);
+
+/**
+ * Increase the number of references to a `PARCBuffer`.
+ *
+ * Note that new `PARCBuffer` is not created,
+ * only that the given `PARCBuffer` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The input `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *x = parcBuffer_Allocate(10);
+ *
+ * PARCBuffer *x_2 = parcBuffer_Acquire(x);
+ *
+ * parcBuffer_Release(&x);
+ * parcBuffer_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Acquire(const PARCBuffer *buffer);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] bufferPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcBuffer_Release(PARCBuffer **bufferPtr);
+
+/**
+ * Returns this buffer's capacity.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given buffer's capacity.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * size_t capacity = parcBuffer_Capacity(buffer);
+ *
+ * parcBuffer_Release(&capacity);
+ * }
+ * @endcode
+ */
+size_t parcBuffer_Capacity(const PARCBuffer *buffer);
+
+/**
+ * Clear the given buffer restoring it to its initial state:
+ * The position is set to zero,
+ * the limit is set to the capacity,
+ * and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * parcBuffer_Clear(buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Clear(PARCBuffer *buffer);
+
+/**
+ * Determine if two `PARCBuffer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBuffer` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcBuffer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcBuffer_Equals(x, y)` must return true if and only if
+ * `parcBuffer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBuffer_Equals(x, y)` returns true and
+ * `parcBuffer_Equals(y, z)` returns true,
+ * then `parcBuffer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcBuffer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcBuffer_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCBuffer` instance.
+ * @param [in] y A pointer to a `PARCBuffer` instance.
+ *
+ * @return true `PARCBuffers` x and y are equal.
+ * @return false `PARCBuffers` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *bufferA = parcBuffer_Allocate(10);
+ * PARCBuffer *bufferB = parcBuffer_Allocate(10);
+ *
+ * if (parcBuffer_Equals(bufferA, bufferB)) {
+ * printf("Buffers are equal.\n");
+ * } else {
+ * printf("Buffers are NOT equal.\n");
+ * }
+ *
+ * parcBuffer_Release(&bufferA);
+ * parcBuffer_Release(&bufferB);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_HashCode
+ */
+bool parcBuffer_Equals(const PARCBuffer *x, const PARCBuffer *y);
+
+/**
+ * Compares instance a with instance b for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as instance
+ * a is less than, equal to, or greater than instance b.
+ *
+ * The buffer's position, limit, and mark are not modified.
+ *
+ * @param [in] a A pointer to the first instance of `PARCBuffer`.
+ * @param [in] b A pointer to the second instance of `PARCBuffer`.
+ *
+ * @return <0 Instance a is less than instance b.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *bufferA = parcBuffer_Allocate(10);
+ * PARCBuffer *bufferB = parcBuffer_Allocate(10);
+ *
+ * if (parcBuffer_Compare(bufferA, bufferB) == 0) {
+ * printf("Buffers are equal.\n");
+ * }
+ *
+ * parcBuffer_Release(&bufferA);
+ * parcBuffer_Release(&bufferB);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Equals
+ */
+int parcBuffer_Compare(const PARCBuffer *a, const PARCBuffer *b);
+
+/**
+ * Return a pointer to the {@link PARCByteArray} that backs this buffer.
+ *
+ * If this `PARCBuffer` has a capacity of zero,
+ * there is no array of bytes and this function returns NULL.
+ *
+ * Modifications to the contents of the `PARCByteArray` will visible to the given
+ * `PARCBuffer` and vice-versa.
+ *
+ * The origin of the given `PARCBuffer` may not be the same as the origin of the underlying
+ * `PARCByteArray`.
+ * Use {@link parcBuffer_ArrayOffset} to obtain the origin of the given `PARCBuffer`
+ * relative to the origin of the underlying `PARCByteArray`
+ *
+ * The caller must obtain its own reference to the `PARCByteArray` if it intends to store it elsewhere.
+ *
+ * Note: Many hard to find bugs can be caused by using this function.
+ * Use the functions provided to manipulate the `PARCBuffer` and its contents.
+ *
+ * @param [in] buffer A `PARCBuffer` pointer.
+ *
+ * @return NULL There is no `PARCByteArray` backing the given `PARCBuffer` (no capacity).
+ * @return non-NULL The pointer to the `PARCByteArray` for the given `PARCBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * PARCByteArray *array = parcBuffer_Array(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Acquire
+ */
+PARCByteArray *parcBuffer_Array(const PARCBuffer *buffer);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * PARCBuffer *copy = parcBuffer_Copy(buffer);
+ *
+ * parcBuffer_Release(&copy);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ */
+PARCBuffer *parcBuffer_Copy(const PARCBuffer *buffer);
+
+/**
+ * Creates a new buffer that shares the original buffer's content.
+ *
+ * The content of the new buffer will be that of this buffer.
+ * Changes to the buffer's content will be visible in both buffers,
+ * however the two buffers' position, limit, and mark values will be independent.
+ *
+ * The new buffer's capacity, limit, position, and mark values will be identical to those of the original buffer.
+ *
+ * @param [in] original The orignal PARCBuffer instance that will be duplicated.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to ta valid `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_Duplicate(buffer2);
+ *
+ * parcBuffer_Release(&buffer);
+ * parcBuffer_Release(&buffer2);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Duplicate(const PARCBuffer *original);
+
+/**
+ * Returns the offset within this buffer's backing {@link PARCByteArray} of the first element.
+ *
+ * Buffer position <i>p</i> corresponds to array index <i>p + arrayOffset()</i>.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return `size_t` The offset within this `PARCBuffer`'s array of the first element of the buffer
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * size_t arrayOffset = parcBuffer_ArrayOffset(buffer);
+ * // offset will be 0 since the contents of the buffer start at the beginning
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcBuffer_ArrayOffset(const PARCBuffer *buffer);
+
+/**
+ * Rewinds this `PARCBuffer`: The position is set to zero and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * parcBuffer_Rewind(buffer); // bring it back to zero
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Rewind(PARCBuffer *buffer);
+
+/**
+ * Resets the given `PARCBuffer`'s position to the previously-marked position.
+ *
+ * Invoking this method neither changes nor invalidates the mark's value.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * buffer = parcBuffer_Reset(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Reset(PARCBuffer *buffer);
+
+/**
+ * Return the given `PARCBuffer`'s limit.
+ *
+ * A buffer's limit is the index of the first element that should not be read or written.
+ * A buffer's limit is never negative and is never greater than its capacity.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given `PARCBuffer`'s limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * size_t limit = parcBuffer_Limit(buffer);
+ * // limit will be 10
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcBuffer_Limit(const PARCBuffer *buffer);
+
+/**
+ * Sets this buffer's mark at its position.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ * parcBuffer_Mark(buffer);
+ * // since the position was 0, the mark remains at 0
+ *
+ * ...
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Mark(PARCBuffer *buffer);
+
+/**
+ * Sets this `PARCBuffer`'s limit.
+ *
+ * If the position is larger than the new limit then it is set to the new limit.
+ *
+ * If the mark is defined and larger than the new limit then the mark is invalidated and
+ * any subsequent operation that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param newLimit The new limit value; must be no larger than this `PARCBuffer`'s capacity.
+ *
+ * @return The given `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * parcBuffer_SetLimit(buffer, 8);
+ *
+ * size_t limit = parcBuffer_Limit(buffer);
+ * size_t capacity = parcBuffer_Capacity(buffer);
+ * // capacity is 10, limit is 8
+ *
+ * ...
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_SetLimit(PARCBuffer *buffer, size_t newLimit);
+
+/**
+ * Return a pointer to buffer memory starting the buffer's current position.
+ *
+ * The @p length parameter must be less than or equal to the remaining bytes in the buffer
+ * and has no effect on the return value,
+ * except that if the buffer's position is equal to the limit, then this traps with OutOfBounds
+ *
+ * The current position of the buffer is advanced by @p length bytes.
+ * It is acceptable for the @p length parameter to be zero,
+ * thereby causing the current position to remain unchanged.
+ *
+ * This does not guarantee any particular memory alignment.
+ * Therefore, it is possible to obtain a pointer to memory that cannot be accessed
+ * as a native type because of CPU architecture alignment requirements.
+ *
+ * The function returns a pointer to contiguous memory within a `PARCBuffer`,
+ * but does not acquire a reference to the `PARCBuffer` instance,
+ * the underlying {@link PARCByteArray}, nor the actual memory array.
+ * If the {@link PARCBuffer} or the underlying {@link PARCByteArray} is released finally,
+ * the result from a previous call to `parcBuffer_Overlay` will point to undefined values.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] length The number of bytes to advance the buffer's position.
+ *
+ * @return non-NULL A pointer to memory.
+ *
+ * Example:
+ * @code
+ * {
+ * char *expected = "Hello World";
+ * struct timeval theTime = { .tv_sec = 123, .tv_usec = 456};
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t) + strlen(expected) + sizeof(theTime));
+ *
+ * parcBuffer_PutUint16(buffer, strlen(expected));
+ * parcBuffer_PutUint8(buffer, expected, strlen(expected));
+ * parcBuffer_PutUint8(buffer, &theTime, sizeof(theTime));
+ * parcBuffer_Flip();
+ *
+ * uint16_t length = parcBuffer_GetUint16(buffer);
+ * char *actual = parcBuffer_Overlay(buffer, length);
+ * struct timeval *tm = parcBuffer_Overlay(buffer, sizeof(struct timeval));
+ * }
+ * @endcode
+ */
+void *parcBuffer_Overlay(PARCBuffer *buffer, size_t length);
+
+/**
+ * Return the given `PARCBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ * @return The given `PARCBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t currentPosition = parcBuffer_Position(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_SetPosition
+ */
+size_t parcBuffer_Position(const PARCBuffer *buffer);
+
+/**
+ * Set the given `PARCBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * If the mark is defined and larger than the new position then the mark
+ * is invalidated and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] newPosition The buffer's new position which must be less than or equal to the current limit.
+ *
+ * @return The given `PARCBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * parcBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Limit
+ */
+PARCBuffer *parcBuffer_SetPosition(PARCBuffer *buffer, size_t newPosition);
+
+/**
+ * Returns the number of elements between the current position and the limit.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The number of elements remaining in this `PARCBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * parcBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ */
+size_t parcBuffer_Remaining(const PARCBuffer *buffer);
+
+/**
+ * Tells whether there are any elements between the current position and the limit.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return true The `PARCBuffer` contains at least one more element.
+ * @return false The `PARCBuffer` does not contain any more elements.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * bool hasRemaining = parcBuffer_HasRemaining(buffer); // returns true since #remaining = 5
+ * }
+ * @endcode
+ */
+bool parcBuffer_HasRemaining(const PARCBuffer *buffer);
+
+/**
+ * Creates a new byte buffer whose content is a shared subsequence of this buffer's content.
+ *
+ * The content of the new buffer will start at this buffer's current position.
+ * Changes to this buffer's content will be visible in the new buffer,
+ * and vice versa;
+ * the two buffers' position, limit,
+ * and mark values will be independent.
+ *
+ * The new buffer's position will be zero,
+ * its capacity and its limit will be the number of bytes remaining in this buffer,
+ * and its mark will be undefined.
+ *
+ * @param [in] original A pointer to a `PARCBuffer` instance.
+ *
+ * @return non-NULL A pointer to a new `PARCBuffer` whose content is a shared subsequence of the original buffer's content.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * parcBuffer_SetLimit(buffer, 8);
+ *
+ * PARCBuffer *slice = parcBuffer_Slice(buffer);
+ * // the slice will be the subset of bytes 5,6,7, and will
+ * // have limit and capacity of 3 (= 8 - 5)
+ *
+ * ...
+ *
+ * parcBuffer_Release(&buffer);
+ * parcBuffer_Release(&slice);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Slice(const PARCBuffer *original);
+
+/**
+ * Set the limit to the current position,
+ * then set the position to zero.
+ * If the mark is defined, it is invalidated.
+ *
+ * Any subsequent operation that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The same value as @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * parcBuffer_Flip(buffer);
+ * uint8_t actual = parcBuffer_GetUint8(buffer);
+ *
+ * ...
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Flip(PARCBuffer *buffer);
+
+/**
+ * Get the single `uint8_t` at the index specified.
+ *
+ * The buffer's position is not modified.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] index The index into the @p buffer to find the `uint8_t`.
+ *
+ * @return The `uint8_t` value at @p index.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * uint8_t actual = parcBuffer_GetAtIndex(buffer, 0);
+ * // actual == (uint8_t) 'X'
+ *
+ * ...
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint8_t parcBuffer_GetAtIndex(const PARCBuffer *buffer, size_t index);
+
+/**
+ * Read the unsigned 8-bit value at the buffer's current position,
+ * and then increment the position by 1.
+ *
+ * @param [in] buffer The pointer to a `PARCBuffer` instance containing the `uint8_t` value.
+ *
+ * @return The `uint8_t` at the buffer's current position
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * parcBuffer_Flip(buffer);
+ * uint8_t actual = parcBuffer_GetUint8(buffer);
+ *
+ * ...
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ */
+uint8_t parcBuffer_GetUint8(PARCBuffer *buffer);
+
+/**
+ * Read the unsigned 16-bit value in network order at the buffer's current position,
+ * and then increment the position by 2.
+ *
+ * @param [in,out] buffer The pointer to the `PARCBuffer` instance containing the value.
+ *
+ * @return The `uint16_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * (buffer, 0x1234);
+ * parcBuffer_Flip(buffer);
+ * uint16_t actual = parcBuffer_GetUint16(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+uint16_t parcBuffer_GetUint16(PARCBuffer *buffer);
+
+/**
+ * Read the unsigned 32-bit value in network order at the buffer's current position,
+ * and then increment the position by the 4.
+ *
+ * @param [in,out] buffer The pointer to the instance of `PARCBuffer` containing the value.
+ *
+ * @return The `uint32_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint32(buffer, 0x12345678);
+ * parcBuffer_Flip(buffer);
+ * uint32_t actual = parcBuffer_GetUint32(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+uint32_t parcBuffer_GetUint32(PARCBuffer *buffer);
+
+/**
+ * Read the unsigned 64-bit value in network order at the buffer's current position,
+ * and then increment the position by 8.
+ *
+ * @param [in,out] buffer The pointer to the instance of `PARCBuffer` containing the value.
+ *
+ * @return The `uint64_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint64(buffer, 0x12345678);
+ * parcBuffer_Flip(buffer);
+ * uint64_t actual = parcBuffer_GetUint64(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+uint64_t parcBuffer_GetUint64(PARCBuffer *buffer);
+
+/**
+ * Read an array of length bytes from the given PARCBuffer, copying them to an array.
+ *
+ * The buffer's position is incremented by @p length.
+ *
+ * @param [in,out] buffer The pointer to the instance of `PARCBuffer` containing the `uint8_t` value.
+ * @param [in] length The number of `uint8_t` elements to get.
+ * @param [in] array The `uint8_t` array to receive @p length bytes.
+ *
+ * @return A pointer to the given `PARCBuffer` instance
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ * parcBuffer_PutUint8(buffer, 'A');
+ * parcBuffer_PutUint8(buffer, 'B');
+ * parcBuffer_PutUint8(buffer, 'C');
+ *
+ * uint8_t array[3];
+ * parcBuffer_GetBytes(buffer, 3, array);
+ * // array[0] == 'A'
+ * // array[1] == 'B'
+ * // array[2] == 'C'
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+PARCBuffer *parcBuffer_GetBytes(PARCBuffer *buffer, size_t length, uint8_t *array);
+
+/**
+ * Insert an unsigned 8-bit value into the given `PARCBuffer` at the current position.
+ *
+ * Advance the current position by 1.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted into the`PARCBuffer` instance at the current position.
+ * @return The `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint8(PARCBuffer *buffer, uint8_t value);
+
+/**
+ * Insert an unsigned 16-bit value into the given `PARCBuffer` at the current position,
+ * in big-endian, network-byte-order.
+ *
+ * Advance the current position by 2.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted
+ * @return The pointer to `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint16(buffer, 0x1234);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint16(PARCBuffer *buffer, uint16_t value);
+
+/**
+ * Insert an unsigned 32-bit value into the given `PARCBuffer` at the current position,
+ * in big-endian, network-byte-order.
+ *
+ * Advance the current position by 4.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted
+ * @return The `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint32(buffer, 0x12345678);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint32(PARCBuffer *buffer, uint32_t value);
+
+/**
+ * Insert an unsigned 64-bit value into the given `PARCBuffer` at the current position,
+ * in big-endian, network-byte-order.
+ *
+ * Advance the current position by 8.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted
+ * @return The `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint64(buffer, 0x1234);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint64(PARCBuffer *buffer, uint64_t value);
+
+/**
+ * Insert unsigned 8-bit value to the given `PARCBuffer` at given index.
+ *
+ * The buffer's position is unchanged.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] index The index at which to insert @p value
+ * @param [in] value The value to be inserted
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutAtIndex(buffer, 3, 'X');
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutAtIndex(PARCBuffer *buffer, size_t index, uint8_t value);
+
+/**
+ * Copy `arrayLength` bytes from the given array into the `PARCBuffer`.
+ *
+ * The position is incremented by `arrayLength`
+ *
+ * @param [in] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] arrayLength The number of bytes to copy into the buffer.
+ * @param [in] array A pointer to the array of bytes.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ *
+ * uint8_t array[3];
+ * array[0] = 'A';
+ * array[1] = 'B';
+ * array[2] = 'C';
+ *
+ * parcBuffer_PutArray(buffer, 3, array);
+ * // the buffer will now contain ['A','B','C'] at indices 0,1,2
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutArray(PARCBuffer *buffer, size_t arrayLength, const uint8_t *array);
+
+/**
+ * Copy the contents of the given nul-terminated C string into a PARCBuffer, including the terminating nul byte.
+ *
+ * The position is incremented by the length of the string plus 1.
+ *
+ * @param [in] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] string A pointer to nul-terminated C string.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ *
+ * char *string = "ABC";
+ *
+ * parcBuffer_PutCString(buffer, string);
+ * // the buffer will now contain ['A','B','C', 0] at indices 0, 1, 2, and 3
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutCString(PARCBuffer *buffer, const char *string);
+
+/**
+ * Put the contents of a `PARCBuffer` into another.
+ *
+ * @param [in] buffer A pointer to the destination `PARCBuffer` instance.
+ * @param [in] source A pointer to the source `PARCBuffer` instance.
+ *
+ * @return The value of @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCBuffer *insertee = parcBuffer_AllocateCString("Hello");
+ * parcBuffer_PutBuffer(buffer, insertee);
+ * // buffer will now contain "Hello" in the first 5 byte indices
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutBuffer(PARCBuffer *buffer, const PARCBuffer *source);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The hash code of a `PARCBuffer` depends only upon its remaining elements from the current position to the limit.
+ *
+ * Because `PARCBuffer` hash codes are content-dependent, be careful when using them as keys in `PARCHashMap`
+ * and other similar data structures unless it is known that their contents will not change.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcByteArray_Equals}
+ * comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcByteArray_Equals} method,
+ * then calling the {@link parcBuffer_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the {@link parcBuffer_Equals} function,
+ * then calling the `parcBuffer_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] buffer A pointer to the `PARCBuffer` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * uint32_t hashValue = parcBuffer_HashCode(buffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_HashCode
+ */
+PARCHashCode parcBuffer_HashCode(const PARCBuffer *buffer);
+
+/**
+ * Return the position of the first `uint8_t` value that matches the given byte.
+ *
+ * If the value does not exist between the current position and the limit,
+ * return `SIZE_MAX` (<stdint.h>).
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] byte The byte to search for within the buffer.
+ *
+ * @return The index of the first byte equal to `byte`, or `SIZE_MAX` (<stdint.h>)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello World", 10, 0, 10);
+ *
+ * size_t ePosition = parcBuffer_FindUint8(buffer, 'e');
+ *
+ * // ePosition is equal to 1.
+ *
+ * size_t xPosition = parcBuffer_FindUint8(buffer, 'x');
+ *
+ * // ePosition is equal to SIZE_MAX.
+ * }
+ * @endcode
+ */
+size_t parcBuffer_FindUint8(const PARCBuffer *buffer, uint8_t byte);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCBuffer`
+ * from the current position to the limit.
+ * The buffer's position is not changed.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] buffer A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * char *helloWorld = "Hello World";
+ * PARCBuffer *instance = parcBuffer_Wrap(helloWorld, strlen(helloWorld), 0, strlen(helloWorld));
+ *
+ * char *string = parcBuffer_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Display
+ */
+char *parcBuffer_ToString(const PARCBuffer *buffer);
+
+/**
+ * Print a human readable representation of the given `PARCBuffer`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] buffer A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *instance = parcBuffer_Create();
+ *
+ * parcBuffer_Display(instance, 0);
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcBuffer_Display(const PARCBuffer *buffer, int indentation);
+
+/**
+ * Return a null-terminated string containing the hex-byte representation of the given `PARCBuffer`.
+ *
+ * The result must be freed by the caller via `parcMemory_Deallocate()`.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *instance = parcBuffer_Create();
+ *
+ * char *hexString = parcBuffer_ToHexString(instance);
+ * parcMemory_Deallocate((void **)&hexString);
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Deallocate
+ */
+char *parcBuffer_ToHexString(const PARCBuffer *buffer);
+
+/**
+ * Advance the position of the given buffer to the first byte that is not in the array @p bytesToSkipOver.
+ *
+ * The position will not exceed the PARCBuffer's limit.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] length Length of the byte array that includes skip bytes
+ * @param [in] bytesToSkipOver A null-terminated array of bytes to skip.
+ *
+ * @return true The `PARCBuffer`'s position was updated.
+ * @return false The `PARCBuffer`'s position reached the limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * uint8_t skipOverBytes[] = { 'H', 0 };
+ *
+ * bool actual = parcBuffer_SkipOver(buffer, 1, skipOverBytes);
+ * // the buffer position will now be 1, as it skipped over the 'H' byte in the array
+ * // actual will be true
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_SkipTo
+ */
+bool parcBuffer_SkipOver(PARCBuffer *buffer, size_t length, const uint8_t *bytesToSkipOver);
+
+/**
+ * Advance the position of the given buffer to the first byte that is in the array @p bytesToSkipTo.
+ *
+ * The position will not exceed the PARCBuffer's limit.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] length Length of the byte array that includes skip bytes
+ * @param [in] bytesToSkipTo A null-terminated array of bytes to find.
+ *
+ * @return true The PARCBuffer's position is at the first byte matched.
+ * @return false The PARCBuffer's position reached the limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * uint8_t skipOverBytes[] = { 'l', 0 };
+ *
+ * bool actual = parcBuffer_SkipTo(buffer, 1, skipOverBytes);
+ * // the buffer position will now be set to the index of the first 'l' byte in the underlying array
+ * // actual will be true
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_SkipOver
+ */
+bool parcBuffer_SkipTo(PARCBuffer *buffer, size_t length, const uint8_t *bytesToSkipTo);
+
+/**
+ * Return the byte at the given `PARCBuffers'` current position, without modifying the position.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The byte at the given `PARCBuffers'` current position
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello");
+ * uint8_t byte = parcBuffer_PeekByte(1);
+ * // byte == (uint8_t) 'e';
+ * }
+ * @endcode
+ */
+uint8_t parcBuffer_PeekByte(const PARCBuffer *buffer);
+
+/**
+ * Parse an ASCII representation of a hexadecimal number in the given `PARCBuffer`
+ *
+ * The number may be prefixed with the characters '0', 'x'.
+ * The buffer's position will be left at the first non-parsable character.
+ *
+ * Overflow is not checked.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ *
+ * @return A uint64_t of the hexadecimal number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("0x10");
+ * uint64_t value = parcBuffer_ParseHexNumber(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint64_t parcBuffer_ParseHexNumber(PARCBuffer *buffer);
+
+/**
+ * Parse an ASCII representation of a unsigned decimal number in the given `PARCBuffer`
+ *
+ * The buffer's position will be left at the first non-parsable character.
+ *
+ * Overflow is not checked.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ *
+ * @return A uint64_t of the decimal number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("100");
+ * uint64_t value = parcBuffer_ParseDecimalNumber(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint64_t parcBuffer_ParseDecimalNumber(PARCBuffer *buffer);
+
+/**
+ * Parse an ASCII representation of a unsigned decimal number or a hexadecimal number in the given `PARCBuffer`
+ *
+ * The buffer's position will be left at the first non-parsable character.
+ *
+ * Overflow is not checked.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ *
+ * @return A uint64_t of the number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("100");
+ * uint64_t value = parcBuffer_ParseNumeric(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint64_t parcBuffer_ParseNumeric(PARCBuffer *buffer);
+#endif // libparc_parc_Buffer_h
diff --git a/libparc/parc/algol/parc_BufferChunker.c b/libparc/parc/algol/parc_BufferChunker.c
new file mode 100644
index 00000000..f3a4ab67
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferChunker.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_BufferChunker.h>
+
+PARCChunkerInterface *PARCBufferChunkerAsChunker = &(PARCChunkerInterface) {
+ .ForwardIterator = (void *(*)(const void *))parcBufferChunker_ForwardIterator,
+ .ReverseIterator = (void *(*)(const void *))parcBufferChunker_ReverseIterator,
+ .GetChunkSize = (size_t (*)(const void *))parcBufferChunker_GetChunkSize
+};
+
+struct _parc_chunker_state {
+ size_t chunkNumber;
+ int direction;
+ bool atEnd;
+ size_t position;
+ size_t nextChunkSize;
+};
+
+typedef struct _parc_chunker_state _ChunkerState;
+
+struct parc_buffer_chunker {
+ // State
+ size_t chunkSize;
+
+ // Container for the data to be parsed
+ PARCBuffer *data;
+
+ // The current element of the iterator
+ PARCBuffer *currentElement;
+};
+
+static void
+_destroy(PARCBufferChunker **chunkerP)
+{
+ if ((*chunkerP)->data != NULL) {
+ parcBuffer_Release(&(*chunkerP)->data);
+ }
+
+ if ((*chunkerP)->currentElement != NULL) {
+ parcBuffer_Release(&(*chunkerP)->currentElement);
+ }
+}
+
+static void *
+_InitForward(PARCBufferChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 0;
+ state->position = 0;
+ state->atEnd = false;
+
+ if (parcBuffer_Remaining(chunker->data) < chunker->chunkSize) {
+ state->nextChunkSize = parcBuffer_Remaining(chunker->data);
+ } else {
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static void *
+_InitReverse(PARCBufferChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 1;
+ state->atEnd = false;
+
+ if (parcBuffer_Remaining(chunker->data) < chunker->chunkSize) {
+ state->position = 0;
+ state->nextChunkSize = parcBuffer_Remaining(chunker->data);
+ } else {
+ state->position = parcBuffer_Remaining(chunker->data) - chunker->chunkSize;
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static bool
+_ccnxChunker_HasNext(PARCBufferChunker *chunker, void *voidstate)
+{
+ _ChunkerState *state = (_ChunkerState *) voidstate;
+ return !state->atEnd;
+}
+
+static void
+_advanceStateForward(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ state->position += state->nextChunkSize;
+
+ size_t remaining = parcBuffer_Remaining(chunker->data);
+
+ if (remaining == 0) {
+ state->atEnd = true;
+ } else if (remaining > chunker->chunkSize) {
+ state->nextChunkSize = chunker->chunkSize;
+ } else {
+ state->nextChunkSize = remaining;
+ }
+}
+
+static void
+_advanceStateBackward(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ // Previous chunk size
+ size_t chunkSize = state->nextChunkSize;
+ if (chunkSize != chunker->chunkSize || state->position == 0) {
+ state->atEnd = true;
+ } else {
+ if (state->position < chunkSize) {
+ state->nextChunkSize = state->position; // on next read, go to the current position
+ state->position = 0; // we reached the beginning
+ } else {
+ state->position -= chunkSize;
+ }
+ }
+}
+
+static void
+_advanceState(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ state->chunkNumber++;
+
+ if (state->direction == 0) {
+ _advanceStateForward(chunker, state);
+ } else {
+ _advanceStateBackward(chunker, state);
+ }
+}
+
+static void *
+_ccnxChunker_NextFromBuffer(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ size_t chunkSize = state->nextChunkSize;
+
+ parcBuffer_SetPosition(chunker->data, state->position);
+ PARCBuffer *slice = parcBuffer_CreateFromArray(parcBuffer_Overlay(chunker->data, chunkSize), chunkSize);
+ slice = parcBuffer_Flip(slice);
+
+ _advanceState(chunker, state);
+
+ return slice;
+}
+
+static void *
+_ccnxChunker_Next(PARCBufferChunker *chunker, void *state)
+{
+ PARCBuffer *buffer = _ccnxChunker_NextFromBuffer(chunker, state);
+
+ if (chunker->currentElement != NULL) {
+ parcBuffer_Release(&chunker->currentElement);
+ }
+ if (buffer != NULL) {
+ chunker->currentElement = parcBuffer_Acquire(buffer);
+ }
+
+ return state;
+}
+
+static void *
+_ccnxChunker_GetElement(PARCBufferChunker *chunker, void *state)
+{
+ return chunker->currentElement;
+}
+
+static void
+_ccnxChunker_Finish(PARCBufferChunker *chunker, void *state)
+{
+ _ChunkerState *thestate = (_ChunkerState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static void
+_ccnxChunker_AssertValid(const void *state)
+{
+ // pass
+}
+
+parcObject_ExtendPARCObject(PARCBufferChunker, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(parcBufferChunker, PARCBufferChunker);
+parcObject_ImplementRelease(parcBufferChunker, PARCBufferChunker);
+
+PARCBufferChunker *
+parcBufferChunker_Create(PARCBuffer *data, size_t chunkSize)
+{
+ PARCBufferChunker *chunker = parcObject_CreateInstance(PARCBufferChunker);
+
+ if (chunker != NULL) {
+ chunker->chunkSize = chunkSize;
+ chunker->data = parcBuffer_Acquire(data);
+ chunker->currentElement = NULL;
+ }
+
+ return chunker;
+}
+
+PARCIterator *
+parcBufferChunker_ForwardIterator(const PARCBufferChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_ccnxChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_Next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_GetElement,
+ (void (*)(PARCObject *, void *))_ccnxChunker_Finish,
+ (void (*)(const void *))_ccnxChunker_AssertValid);
+
+ return iterator;
+}
+
+PARCIterator *
+parcBufferChunker_ReverseIterator(const PARCBufferChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitReverse,
+ (bool (*)(PARCObject *, void *))_ccnxChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_Next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_GetElement,
+ (void (*)(PARCObject *, void *))_ccnxChunker_Finish,
+ (void (*)(const void *))_ccnxChunker_AssertValid);
+
+ return iterator;
+}
+
+size_t
+parcBufferChunker_GetChunkSize(const PARCBufferChunker *chunker)
+{
+ return chunker->chunkSize;
+}
diff --git a/libparc/parc/algol/parc_BufferChunker.h b/libparc/parc/algol/parc_BufferChunker.h
new file mode 100755
index 00000000..16f21c49
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferChunker.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_BufferChunker.h
+ * @ingroup ContentObject
+ * @brief A BufferChunker is a chunker that segments a PARCBuffer.
+ *
+ */
+
+#ifndef libparc_parc_BufferChunker_h
+#define libparc_parc_BufferChunker_h
+
+#include <parc/algol/parc_Chunker.h>
+
+struct parc_buffer_chunker;
+/**
+ * @typedef PARCChunker
+ * @brief The PARC Chunker
+ */
+typedef struct parc_buffer_chunker PARCBufferChunker;
+
+/**
+ * The mapping of a `PARCBufferChunker` to the generic `PARCChunker`.
+ */
+extern PARCChunkerInterface *PARCBufferChunkerAsChunker;
+
+/**
+ * Create a new chunker to segment data contained in a `PARCBuffer.`
+ *
+ * @param [in] data A `PARCBuffer` which contains the data.
+ * @param [in] chunkSize The size per chunk.
+ *
+ * @retval PARCChunker A newly allocated `PARCChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunker = ccnxChunker_CreateFromBuffer(dataToChunk, 32);
+ * }
+ */
+PARCBufferChunker *parcBufferChunker_Create(PARCBuffer *data, size_t chunkSize);
+
+/**
+ * Increase the number of references to a `PARCChunker` instance.
+ *
+ * Note that new `PARCChunker` is not created,
+ * only that the given `PARCChunker` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxChunker_Release}.
+ *
+ * @param [in] chunker A pointer to the original `PARCChunker`.
+ * @return The value of the input parameter @p chunker.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferChunker *original = parcBufferChunker_Create(...);
+ *
+ * PARCBufferChunker *reference = parcBufferChunker_Acquire(original);
+ *
+ * parcBufferChunker_Release(&original);
+ * parcBufferChunker_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcBufferChunker_Release
+ */
+PARCBufferChunker *parcBufferChunker_Acquire(const PARCBufferChunker *chunker);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] chunkerP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCBufferChunker *chunker = parcBufferChunker_Acquire(instance);
+ *
+ * parcBufferChunker_Release(&chunker);
+ * }
+ * @endcode
+ */
+void parcBufferChunker_Release(PARCBufferChunker **chunkerP);
+
+/**
+ * Determine if two `PARCBufferChunker` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBufferChunker` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcBufferChunker_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcBufferChunker_Equals(x, y)` must return true if and only if
+ * `parcBufferChunker_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBufferChunker_Equals(x, y)` returns true and
+ * `parcBufferChunker_Equals(y, z)` returns true,
+ * then `parcBufferChunker_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcBufferChunker_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcBufferChunker_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param chunkerA A pointer to a `PARCBufferChunker` instance.
+ * @param chunkerB A pointer to a `PARCBufferChunker` instance.
+ * @return true if the two `PARCBufferChunker` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunkerA = parcBufferChunker_Create(dataToChunk, 32);
+ * PARCBufferChunker *chunkerB = parcBufferChunker_Create(dataToChunk, 32);
+ *
+ * bool equals = parcBufferChunker_Equals(chunkerA, chunkerB);
+ * }
+ * @endcode
+ */
+bool parcBufferChunker_Equals(const PARCBufferChunker *chunkerA, const PARCBufferChunker *chunkerB);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCBufferChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = parcBufferChunker_Create(dataToChunk, 32);
+ *
+ * PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcBufferChunker_ForwardIterator(const PARCBufferChunker *chunker);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCBufferChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = parcBufferChunker_Create(dataToChunk, 32);
+ *
+ * PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcBufferChunker_ReverseIterator(const PARCBufferChunker *chunker);
+
+/**
+ * Get the chunk size of a `PARCBufferChunker.`
+ *
+ * @param [in] chunker A `PARCBufferChunker` instance.
+ *
+ * @return the chunk size
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = ...
+ *
+ * size_t chunkSize = parcBufferChunker_GetChunkSize(chunker);
+ * }
+ * @endcode
+ */
+size_t parcBufferChunker_GetChunkSize(const PARCBufferChunker *chunker);
+#endif // libparc_parc_BufferChunker_h
diff --git a/libparc/parc/algol/parc_BufferComposer.c b/libparc/parc/algol/parc_BufferComposer.c
new file mode 100755
index 00000000..20b7ecee
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferComposer.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_buffer_composer {
+ size_t incrementHeuristic;
+ PARCBuffer *buffer;
+};
+
+static void
+_finalize(PARCBufferComposer **bufferPtr)
+{
+ if (bufferPtr != NULL) {
+ PARCBufferComposer *composer = *bufferPtr;
+ parcBufferComposer_OptionalAssertValid(composer);
+ if (composer->buffer != NULL) {
+ parcBuffer_Release(&composer->buffer);
+ }
+ }
+}
+
+parcObject_ExtendPARCObject(PARCBufferComposer, _finalize, NULL, NULL, parcBufferComposer_Equals, NULL, NULL, NULL);
+
+static PARCBufferComposer *
+_create(void)
+{
+ return parcObject_CreateInstance(PARCBufferComposer);
+}
+
+/**
+ * Ensure that the given `PARCBufferComposer` has at least the required number of bytes remaining.
+ *
+ * If the remaining capacity (the difference between the capacity of the buffer and its current position)
+ * of the underlying `PARCBuffer` is less than the required number of bytes,
+ * the underlying PARCBuffer is expanded with sufficient space to accomodate the required number of bytes.
+ *
+ * The position, limit, and mark remain unchanged.
+ * The capacity is increased.
+ */
+static PARCBufferComposer *
+_ensureRemaining(PARCBufferComposer *composer, size_t required)
+{
+ parcBufferComposer_OptionalAssertValid(composer);
+
+ size_t remainingCapacity = parcBuffer_Capacity(composer->buffer) - parcBuffer_Position(composer->buffer);
+
+ if (remainingCapacity < required) {
+ size_t incrementAmount = required;
+ if (incrementAmount < composer->incrementHeuristic) {
+ incrementAmount = composer->incrementHeuristic;
+ }
+ size_t newCapacity = parcBuffer_Capacity(composer->buffer) + incrementAmount;
+
+ PARCBuffer *newBuffer = parcBuffer_Allocate(newCapacity);
+ parcBuffer_Flip(composer->buffer);
+ parcBuffer_PutBuffer(newBuffer, composer->buffer);
+ parcBuffer_Release(&composer->buffer);
+ composer->buffer = newBuffer;
+ }
+
+ return composer;
+}
+
+void
+parcBufferComposer_AssertValid(const PARCBufferComposer *composer)
+{
+ trapIllegalValueIf(composer == NULL, "Parameter must be a non-null pointer to a valid PARCBufferComposer.");
+ trapIllegalValueIf(composer->incrementHeuristic < sizeof(void *), "Heuristic cannot be < sizeof(void *) (%zd), actual %zd", sizeof(void *), composer->incrementHeuristic);
+}
+
+PARCBufferComposer *
+parcBufferComposer_Create(void)
+{
+ return parcBufferComposer_Allocate(parcMemory_RoundUpToCacheLine(LEVEL1_DCACHE_LINESIZE));
+}
+
+PARCBufferComposer *
+parcBufferComposer_Allocate(size_t size)
+{
+ PARCBufferComposer *result = _create();
+ if (result != NULL) {
+ result->buffer = parcBuffer_Allocate(size);
+ result->incrementHeuristic = parcMemory_RoundUpToCacheLine(size);
+ if (result->buffer == NULL) {
+ result->incrementHeuristic = sizeof(void *); // minimum size
+ parcBufferComposer_Release(&result);
+ }
+ }
+ return result;
+}
+
+parcObject_ImplementAcquire(parcBufferComposer, PARCBufferComposer);
+
+parcObject_ImplementRelease(parcBufferComposer, PARCBufferComposer);
+
+bool
+parcBufferComposer_Equals(const PARCBufferComposer *x, const PARCBufferComposer *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->incrementHeuristic == y->incrementHeuristic) {
+ if (parcBuffer_Equals(x->buffer, y->buffer)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutArray(PARCBufferComposer *composer, const unsigned char *bytes, size_t length)
+{
+ if (length > 0) {
+ composer = _ensureRemaining(composer, length);
+ if (composer != NULL) {
+ parcBuffer_PutArray(composer->buffer, length, bytes);
+ }
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutChar(PARCBufferComposer *composer, char val)
+{
+ return parcBufferComposer_PutUint8(composer, (uint8_t) val);
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint8(PARCBufferComposer *composer, uint8_t byte)
+{
+ composer = _ensureRemaining(composer, 1);
+ if (composer != NULL) {
+ parcBuffer_PutUint8(composer->buffer, byte);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint16(PARCBufferComposer *composer, uint16_t value)
+{
+ composer = _ensureRemaining(composer, 2);
+ if (composer != NULL) {
+ parcBuffer_PutUint16(composer->buffer, value);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint32(PARCBufferComposer *composer, uint32_t value)
+{
+ composer = _ensureRemaining(composer, 4);
+ if (composer != NULL) {
+ parcBuffer_PutUint32(composer->buffer, value);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint64(PARCBufferComposer *composer, uint64_t value)
+{
+ composer = _ensureRemaining(composer, 8);
+ if (composer != NULL) {
+ parcBuffer_PutUint64(composer->buffer, value);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutBuffer(PARCBufferComposer *composer, const PARCBuffer *source)
+{
+ composer = _ensureRemaining(composer, parcBuffer_Remaining(source));
+ if (composer != NULL) {
+ parcBuffer_PutBuffer(composer->buffer, source);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutString(PARCBufferComposer *composer, const char *string)
+{
+ PARCBuffer *wrapper = parcBuffer_AllocateCString(string);
+
+ composer = _ensureRemaining(composer, parcBuffer_Remaining(wrapper));
+ if (composer != NULL) {
+ parcBuffer_PutBuffer(composer->buffer, wrapper);
+ }
+
+ parcBuffer_Release(&wrapper);
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutStrings(PARCBufferComposer *composer, ...)
+{
+ va_list ap;
+ va_start(ap, composer);
+
+ char *arg;
+ while ((arg = va_arg(ap, char *)) != NULL) {
+ parcBufferComposer_PutString(composer, arg);
+ }
+ va_end(ap);
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_Format(PARCBufferComposer *composer, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *cString;
+ ssize_t written = vasprintf(&cString, format, ap);
+ assertTrue(written >= 0, "Got error from vasprintf");
+ va_end(ap);
+
+ parcBufferComposer_PutString(composer, cString);
+ free(cString);
+
+ return composer;
+}
+
+PARCBuffer *
+parcBufferComposer_GetBuffer(const PARCBufferComposer *composer)
+{
+ return composer->buffer;
+}
+
+PARCBuffer *
+parcBufferComposer_CreateBuffer(PARCBufferComposer *composer)
+{
+ return parcBuffer_Duplicate(composer->buffer);
+}
+
+PARCBuffer *
+parcBufferComposer_ProduceBuffer(PARCBufferComposer *composer)
+{
+ return parcBuffer_Acquire(parcBuffer_Flip(composer->buffer));
+}
+
+char *
+parcBufferComposer_ToString(PARCBufferComposer *composer)
+{
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_Duplicate(composer->buffer));
+
+ char *result = parcBuffer_ToString(buffer);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_BufferComposer.h b/libparc/parc/algol/parc_BufferComposer.h
new file mode 100755
index 00000000..f45aeb8e
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferComposer.h
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_BufferComposer.h
+ * @ingroup memory
+ * @brief An elastic memory composer of PARCBuffer instances.
+ *
+ * A `PARCBufferComposer` is a dynamically allocated buffer that can be used to incrementally add (append)
+ * intrinsic values and/or `PARCBuffer` instance contents to a single location. It is meant to be a general
+ * purpose buffer in that all native types may be added to the buffer. When finished, the user can finalize
+ * the composer and produce a flipped `PARCBuffer` instance.
+ *
+ */
+#ifndef libparc_parc_BufferComposer_h
+#define libparc_parc_BufferComposer_h
+
+struct parc_buffer_composer;
+typedef struct parc_buffer_composer PARCBufferComposer;
+
+#include <parc/algol/parc_Buffer.h>
+
+extern parcObjectDescriptor_Declaration(PARCBufferComposer);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcBufferComposer_OptionalAssertValid(_instance_)
+#else
+# define parcBufferComposer_OptionalAssertValid(_instance_) parcBufferComposer_AssertValid(_instance_)
+#endif
+
+/**
+ * Create an empty (zero-length) `PARCBufferComposer`.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to the new `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Create();
+ *
+ * // insert contents...
+ *
+ * parcBufferComposer_Release(&composer);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Create(void);
+
+/**
+ * Create a new instance of `PARCBufferComposer` starting with an initial amount of dynamically allocated memory.
+ *
+ * The new buffer's position will be zero, its limit will be set to `length`, its capacity will be set to limit,
+ * its mark will be undefined, and each of its elements will be initialized to zero.
+ *
+ * @param [in] length The number of bytes to pre-allocate.
+ *
+ * @return A pointer to a `PARCBufferComposer` instance
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *buffer = parcBufferComposer_Allocate(10);
+ *
+ * parcBufferComposer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Allocate(size_t length);
+
+/**
+ * Assert that an instance of `PARCBufferComposer` is valid.
+ *
+ * If the instance is not valid, terminate via `trapIllegalValue()`.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a PARCBufferComposer instance.
+ */
+void parcBufferComposer_AssertValid(const PARCBufferComposer *instance);
+
+/**
+ * This function returns a pointer to a shared `PARCBufferComposer`.
+ * An implementation may choose to produce a whole copy of the original `PARCBufferComposer`,
+ * or a reference counted pointer to a common copy.
+ *
+ * {@link parcBufferComposer_Release()} must perform the right operations to take care of a shared `PARCBufferComposer`,
+ * or simple copies.
+ *
+ * @param [in] original A pointer to a `PARCBufferComposer` that will be copied.
+ *
+ * @return A pointer to a `PARCBufferComposer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *buffer = parcBufferComposer_Allocate(10);
+ *
+ * PARCBufferComposer *handle = parcBufferComposer_Acquire(buffer);
+ * // handle and buffer will be equal
+ *
+ * parcBufferComposer_Release(&handle);
+ * parcBufferComposer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Acquire(const PARCBufferComposer *original);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] composerPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Create();
+ *
+ * parcBufferComposer_Release(&composer);
+ * }
+ * @endcode
+ */
+void parcBufferComposer_Release(PARCBufferComposer **composerPtr);
+
+/**
+ * Determine if two `PARCBufferComposer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBufferComposer` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcBufferComposer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcBufferComposer_Equals(x, y)` must return true if and only if
+ * `parcBufferComposer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBufferComposer_Equals(x, y)` returns true and
+ * `parcBufferComposer_Equals(y, z)` returns true,
+ * then `parcBufferComposer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcBufferComposer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcBufferComposer_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCBufferComposer` instance.
+ * @param [in] y A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return true `PARCBufferComposer` x and y are equal.
+ * @return false `PARCBufferComposer` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composerA = parcBuffer_Allocate(10);
+ * PARCBufferComposer *composerB = parcBuffer_Allocate(10);
+ *
+ * if (parcBufferComposer_Equals(composerA, composerB)) {
+ * printf("Composers are equal.\n");
+ * } else {
+ * printf("Composers are NOT equal.\n");
+ * }
+ *
+ * parcBufferComposer_Release(&composerA);
+ * parcBufferComposer_Release(&composerB);
+ * }
+ * @endcode
+ */
+bool parcBufferComposer_Equals(const PARCBufferComposer *x, const PARCBufferComposer *y);
+
+/**
+ * Append `length` number of bytes from the given byte array `bytes` to the given `PARCBufferComposer`.
+ *
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to the PARCBufferComposer to receive the data.
+ * @param [in] bytes A pointer to the array that contains the data.
+ * @param [in] length The number of bytes of data to put into @p buffer.
+ *
+ * @return NULL Memory could not be allocated, and the buffer is unmodified.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * uint8_t string[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
+ *
+ * parcBufferComposer_PutArray(composer, string, strlen(string));
+ *
+ * parcBufferComposer_Release(&composer);
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutArray(PARCBufferComposer *composer, const unsigned char *bytes, size_t length);
+
+/**
+ * Append a single char to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 1 (== sizeof(char)).
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the char value.
+ * @param [in] value A single char value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutChar(composer, 0x12);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutChar(PARCBufferComposer *composer, char value);
+
+/**
+ * Append a single uint8_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 1 (== sizeof(uint8_t)).
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint8_t value.
+ * @param [in] value A uint8_t value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutUint8(composer, 0x12);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint8(PARCBufferComposer *composer, uint8_t value);
+
+/**
+ * Append a single uint16_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 2.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint16_t value.
+ * @param [in] value A uint16_t value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutUint16(composer, 0x1234);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint16(PARCBufferComposer *composer, uint16_t value);
+
+/**
+ * Append a single uint16_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 4.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint32_t value.
+ * @param [in] value A `uint32_t` value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutUint32(composer, 0x12345678);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint32(PARCBufferComposer *composer, uint32_t value);
+
+/**
+ * Append a single uint64_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The value is encoded in full, 8 byte, form in big-endian format, or network byte order.
+ * The buffer's position will be advanced by 8.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint64_t value.
+ * @param [in] value A `uint64_t` value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(20);
+ * parcBufferComposer_PutUint32(composer, 0x0123456789ABCDEF);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint64(PARCBufferComposer *composer, uint64_t value);
+
+/**
+ * Put (append) the content of the source buffer into the destination buffer.
+ *
+ * The contents are taken from the current position of the source buffer
+ * to its limit. The destination buffer is expanded as necessary.
+ *
+ * When complete, the source buffer's position is set to its limit.
+ *
+ * Both the input `PARCBufferComposer` and `PARCBuffer` instances are modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance.
+ * @param [in] sourceBuffer The buffer that will produce the data.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBufferComposer *parcBufferComposer_PutBuffer(PARCBufferComposer *composer, const PARCBuffer *sourceBuffer);
+
+/**
+ * Put (append) the content of the null-terminated, C-style string into the destination buffer.
+ *
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance.
+ * @param [in] cString A pointer to a null-terminated C string to append to this `PARCBufferComposer`.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * parcBufferComposer_PutString(composer, "Hello, World!");
+ * // Hello, World!
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_PutBuffer
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBufferComposer *parcBufferComposer_PutString(PARCBufferComposer *composer, const char *cString);
+
+/**
+ * Put (append) the content of an arbitrary number of null-terminated, C-style strings
+ * into the destination buffer.
+ *
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance.
+ * @param [in] ... The null-terminated, C-style strings to append to the given `PARCBufferComposer`.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * parcBufferComposer_PutString(composer, "Hello");
+ * parcBufferComposer_PutStrings(composer, ", ", "World", "!");
+ * // Hello, World!
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_PutString
+ * @see parcBufferComposer_PutBuffer
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBufferComposer *parcBufferComposer_PutStrings(PARCBufferComposer *composer, ...);
+
+/**
+ * Append a formatted nul-terminated, C string string to the given `PARCBufferComposer` instance.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * The format string is a nul-terminated C string compatible with the `vasprintf(3)` C library function.
+ *
+ * @param [in,out] composer A pointer to `PARCBufferComposer`.
+ * @param [in] format The format string compatible with the `vasprintf(3)` C library function.
+ * @param [in] ... Remaining parameters used to format the string.
+ *
+ * @return The same pointer as the `composer` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ *
+ * parcBufferComposer_Format(composer, "Hello %s\n", "World");
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(string)));
+ * printf("String = %s\n", string);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Format(PARCBufferComposer *composer, const char *format, ...)
+__attribute__((format(printf, 2, 3)));
+
+/**
+ * Return a pointer to the underlying {@link PARCBuffer} instance currently used by the given `PARCBufferComposer`.
+ *
+ * WARNING: This function is not safe. Use with caution.
+ *
+ * There is no guarantee that the returned `PARCBuffer` instance will not
+ * be released and deallocated before use by the caller of this function.
+ * If modifications need to be made, a reference should be acquired manually.
+ *
+ * Also, if the caller modifies the state of the returned `PARCBuffer` instance,
+ * e.g., via a {@link parcBuffer_GetUint8}() call, any future writes to this
+ * same `PARCBufferComposer` will not behave as expected unless the instance is
+ * returned to its original state.
+ *
+ * To safely access the underlying `PARCBuffer` instance, use
+ * the {@link parcBufferComposer_CreateBuffer}() function instead.
+ *
+ * No new reference is created. The caller must acquire a reference to the returned `PARCBuffer`
+ * if it needs retain it beyond the life of the given `PARCBufferComposer`.
+ *
+ * @param composer [in] A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return A pointer to the internal `PARCBuffer` which is wrapped by this `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ *
+ * PARCBuffer *sameBuffer = parcBufferComposer_GetBuffer(composer);
+ * // buffer and sameBuffer are equal
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_PutBuffer
+ * @see parcBufferComposer_ProduceBuffer
+ */
+PARCBuffer *parcBufferComposer_GetBuffer(const PARCBufferComposer *composer);
+
+/**
+ * Create a `PARCBuffer` pointing to the underlying `PARCBuffer` instance.
+ *
+ * This is functionally equivalent to {@link parcBufferComposer_GetBuffer} but
+ * is safe since it allocates a new `PARCBuffer` instance for the same buffer.
+ *
+ * The result must be freed by the caller via {@link parcBuffer_Release}.
+ *
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return A pointer to the `PARCBuffer` which is stored by this `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ *
+ * PARCBuffer *writeBuffer = parcBufferComposer_CreateBuffer(composer);
+ *
+ * // use writeBuffer as needed
+ *
+ * parcBuffer_Release(&writeBuffer);
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_GetBuffer
+ * @see parcBufferComposer_ProduceBuffer
+ */
+PARCBuffer *parcBufferComposer_CreateBuffer(PARCBufferComposer *composer);
+
+/**
+ * Finalize this `PARCBufferComposer` and return the resulting {@link PARCBuffer}.
+ *
+ * Note that, unlike {@link parcBufferComposer_GetBuffer}, the return buffer is flipped
+ * via {@link parcBuffer_Flip}. This effectively finalizes this `PARCBufferComposer`.
+ * No more writes should be made to this instance.
+ *
+ * Also note that {@link parcBufferComposer_ToString} cannot be called after this function
+ * is invoked.
+ *
+ * The result must be freed by the caller via {@link parcBuffer_Release}.
+ *
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return A pointer to the final `PARCBuffer` which is stored by this `PARCBufferComposer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ *
+ * PARCBuffer *readBuffer = parcBufferComposer_ProduceBuffer(composer);
+ * parcBufferComposer_Release(&composer);
+ *
+ * // use readBuffer as needed
+ *
+ * parcBuffer_Release(&readBuffer);
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBuffer *parcBufferComposer_ProduceBuffer(PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string containing the characters from 0 to the current
+ * position of the given `PARCBufferComposer`.
+ * The composer is not modified and may continue to be used.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCBufferComposer instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *a = parcBufferComposer_Create();
+ *
+ * char *string = parcBufferComposer_ToString(a);
+ *
+ * parcBufferComposer_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ */
+char *parcBufferComposer_ToString(PARCBufferComposer *composer);
+#endif // libparc_parc_BufferComposer_h
diff --git a/libparc/parc/algol/parc_BufferDictionary.c b/libparc/parc/algol/parc_BufferDictionary.c
new file mode 100755
index 00000000..56ed800a
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferDictionary.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The dictionary is implemented with the parc_HashCodeTable backend. This implementation
+ * is inefficient for additions with duplicate keys, because the semantics of parc_HashCodeTable
+ * are not the same as parc_BufferDictionary in returning values for Put and Remove.
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_BufferDictionary.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_HashCodeTable.h>
+
+struct parc_buffer_dictionary {
+ PARCHashCodeTable *hashtable;
+};
+
+// Wrapper to go from void * to PARCBuffer *
+static bool
+_parcBufferEquals(const void *a, const void *b)
+{
+ return parcBuffer_Equals((const PARCBuffer *) a, (const PARCBuffer *) b);
+}
+
+// Wrapper to go from void * to PARCBuffer *
+static PARCHashCode
+_parcBufferHashCode(const void *a)
+{
+ return parcBuffer_HashCode((const PARCBuffer *) a);
+}
+
+// Wrapper to go from void ** to PARCBuffer **
+static void
+_parcBufferRelease(void **bufferVoidPtr)
+{
+ parcBuffer_Release((PARCBuffer **) bufferVoidPtr);
+}
+
+/*
+ * Initialise a parcBufferDictionary instance.
+ * @return The same pointer as `result`.
+ */
+static PARCBufferDictionary *
+_init(PARCBufferDictionary *result)
+{
+ result->hashtable = parcHashCodeTable_Create(_parcBufferEquals, _parcBufferHashCode, _parcBufferRelease, _parcBufferRelease);
+ return result;
+}
+
+/**
+ * Cleans up the internal memory of a PARCBufferDictionary
+ *
+ * @param [in] dictionaryPtr Double pointer to the dictionary to finalize
+ */
+static void
+_destroy(PARCBufferDictionary **dictionaryPtr)
+{
+ assertNotNull(dictionaryPtr, "Double pointer dictionaryPtr must be non-NULL");
+ assertNotNull(*dictionaryPtr, "Double pointer dictionaryPtr must dereference to non-NULL");
+
+ PARCBufferDictionary *dict = *dictionaryPtr;
+
+ parcHashCodeTable_Destroy(&dict->hashtable);
+}
+
+
+parcObject_ExtendPARCObject(PARCBufferDictionary, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCBufferDictionary *
+parcBufferDictionary_Create(void)
+{
+ PARCBufferDictionary *result = parcObject_CreateInstance(PARCBufferDictionary);
+ if (result != NULL) {
+ return _init(result);
+ }
+
+ return NULL;
+}
+
+parcObject_ImplementAcquire(parcBufferDictionary, PARCBufferDictionary);
+
+parcObject_ImplementRelease(parcBufferDictionary, PARCBufferDictionary);
+
+PARCBuffer *
+parcBufferDictionary_Put(PARCBufferDictionary *dictionary, PARCBuffer *key, PARCBuffer *value)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-NULL");
+ assertNotNull(key, "Parameter key must be non-NULL");
+ assertNotNull(value, "Parameter value must be non-NULL");
+
+ PARCBuffer *oldValue = NULL;
+
+ // We use reference counted copyies of the supplied parameters
+ PARCBuffer *key_copy = parcBuffer_Acquire(key);
+ PARCBuffer *value_copy = parcBuffer_Acquire(value);
+
+ if (!parcHashCodeTable_Add(dictionary->hashtable, key_copy, value_copy)) {
+ // parcHashCodeTable_Del will free the referece, to make a copy of it
+ PARCBuffer *original = (PARCBuffer *) parcHashCodeTable_Get(dictionary->hashtable, key_copy);
+ oldValue = parcBuffer_Acquire(original);
+ parcHashCodeTable_Del(dictionary->hashtable, key_copy);
+ parcHashCodeTable_Add(dictionary->hashtable, key_copy, value_copy);
+ }
+
+ return oldValue;
+}
+
+PARCBuffer *
+parcBufferDictionary_Get(PARCBufferDictionary *dictionary, PARCBuffer *key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-NULL");
+ assertNotNull(key, "Parameter key must be non-NULL");
+
+ return parcHashCodeTable_Get(dictionary->hashtable, key);
+}
+
+PARCBuffer *
+parcBufferDictionary_Remove(PARCBufferDictionary *dictionary, PARCBuffer *key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-NULL");
+ assertNotNull(key, "Parameter key must be non-NULL");
+
+ // parcHashCodeTable_Del will free the referece, to make a copy of it
+ PARCBuffer *original = (PARCBuffer *) parcHashCodeTable_Get(dictionary->hashtable, key);
+ PARCBuffer *oldValue = parcBuffer_Acquire(original);
+ parcHashCodeTable_Del(dictionary->hashtable, key);
+ return oldValue;
+}
diff --git a/libparc/parc/algol/parc_BufferDictionary.h b/libparc/parc/algol/parc_BufferDictionary.h
new file mode 100755
index 00000000..60aa90cb
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferDictionary.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_BufferDictionary.h
+ * @ingroup datastructures
+ * @brief A key/value dictionary built around PARCBuffer as the Key and the Value.
+ *
+ * The key/value dictionary models the Java MAP interface. It is built around Put, Get, and Remove.
+ * The dictionary stores references to the Key and Value, so the caller may destroy its references
+ * if no longer needed.
+ *
+ */
+#ifndef libparc_parc_BufferDictionary_h
+#define libparc_parc_BufferDictionary_h
+
+typedef struct parc_buffer_dictionary PARCBufferDictionary;
+
+#include <parc/algol/parc_Buffer.h>
+
+
+/**
+ * Creates an empty dictionary. You must use {@link parcBufferDictionary_Release} to destroy it.
+ *
+ * @return A pointer to the new `PARCBufferDictionary`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferDictionary *parcBufferDictionary_Create(void);
+
+/**
+ * Increase the number of references to a `PARCBufferDictionary`.
+ *
+ * Note that a new `PARCBufferDictionary` is not created,
+ * only that the given `PARCBufferDictionary` reference count is incremented.
+ * Discard the reference by invoking {@link parcBufferDictionary_Release}.
+ *
+ * @param [in] dictionary is a pointer to a `PARCBufferDictionary` instance
+ * @return The pointer to the @p dictionary instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferDictionary *parcBufferDictionary_Acquire(const PARCBufferDictionary *dictionary);
+
+/**
+ * Release a `PARCBufferDictionary` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCBufferDictionary`.
+ *
+ * @param [in,out] dictionaryPtr is a pointer to the `PARCBufferDictionary` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcBufferDictionary_Release(PARCBufferDictionary **dictionaryPtr);
+
+/**
+ * Add a key/value to the dictionary, returns previous value or NULL
+ *
+ * The Dictionary will store a reference (PARCBuffer::aquire) to the key and to the value.
+ * The Key and Value must be non-NULL. If a previous entry for the key is in the dictionary,
+ * the previous value is returned. THE CALLER MUST USE {@link parcBuffer_Release} on the returned
+ * value if it is non-NULL;
+ *
+ * @param [in,out] dictionary The dictionary to modify
+ * @param [in] key The dictionary key
+ * @param [in] value The value for the key
+ *
+ * @return NULL The inserted key is unique
+ * @return non-NULL Returns the previous value of the key, must use {@link parcBuffer_Release}
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcBufferDictionary_Put(PARCBufferDictionary *dictionary, PARCBuffer *key, PARCBuffer *value);
+
+/**
+ * Returns the value associated with the key, or NULL if does not exist
+ *
+ * The returned value is what's stored in the dictionary in a `PARCBuffer` instance. If the user wishes to keep the
+ * value beyond the current calling scope, she should use {@link parcBuffer_Acquire} on the
+ * returned value.
+ *
+ * @param [in] dictionary The dictionary to query
+ * @param [in] key The dictionary key
+ *
+ * @return NULL The key is not in the dictionary
+ * @return non-NULL Returns the current value of the key, DO NOT use {@link parcBuffer_Release}
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcBufferDictionary_Get(PARCBufferDictionary *dictionary, PARCBuffer *key);
+
+/**
+ * Removes a key from the dictionary, returning the current value or NULL. The caller MUST
+ * call {@link parcBuffer_Release} on the returned value.
+ *
+ * @param [in,out] dictionary The dictionary to modify
+ * @param [in] key The dictionary key
+ *
+ * @return NULL The inserted key is not in the dictionary
+ * @return non-NULL Returns the current value of the key, DO NOT use {@link parcBuffer_Release}
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t phone[] = "6505551212";
+ * PARCBufferDictionary *dict = parcBufferDictionary_Create();
+ *
+ * parcBuffer *key = parcBuffer_Wrap(phone, sizeof(phone), 0);
+ * parcBuffer_Release(parcBufferDictionary_Remove(dict, key));
+ *
+ * parcBuffer_Release(&key);
+ * parcBufferDictionary_Destroy(&dict);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBufferDictionary_Remove(PARCBufferDictionary *dictionary, PARCBuffer *key);
+#endif // libparc_parc_BufferDictionary_h
diff --git a/libparc/parc/algol/parc_ByteArray.c b/libparc/parc/algol/parc_ByteArray.c
new file mode 100644
index 00000000..762421bd
--- /dev/null
+++ b/libparc/parc/algol/parc_ByteArray.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ByteArray.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_byte_array {
+ uint8_t *array;
+ size_t length;
+ void (*freeFunction)(void **);
+};
+#define MAGIC 0x0ddba11c1a55e5
+
+static inline void
+_trapIfOutOfBounds(const PARCByteArray *array, const size_t index)
+{
+ trapOutOfBoundsIf(index >= array->length, "parcByteArray index %zd exceeds the length %zd", index, array->length);
+}
+
+static bool
+_parcByteArray_Destructor(PARCByteArray **byteArrayPtr)
+{
+ PARCByteArray *byteArray = *byteArrayPtr;
+
+ if (byteArray->freeFunction != NULL) {
+ if (byteArray->array != NULL) {
+ byteArray->freeFunction((void **) &(byteArray->array));
+ }
+ }
+ return true;
+}
+
+parcObject_Override(PARCByteArray, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcByteArray_Destructor,
+ .copy = (PARCObjectCopy *) parcByteArray_Copy,
+ .equals = (PARCObjectEquals *) parcByteArray_Equals,
+ .compare = (PARCObjectCompare *) parcByteArray_Compare,
+ .hashCode = (PARCObjectHashCode *) parcByteArray_HashCode,
+ .display = (PARCObjectDisplay *) parcByteArray_Display);
+
+void
+parcByteArray_AssertValid(const PARCByteArray *instance)
+{
+ trapInvalidValueIf(parcByteArray_IsValid(instance) == false,
+ "PARCByteArray instance is invalid.");
+}
+
+bool
+parcByteArray_IsValid(const PARCByteArray *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->length == 0 || instance->array != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCByteArray *
+parcByteArray_Allocate(const size_t length)
+{
+ uint8_t *array = NULL;
+ if (length > 0) {
+ array = parcMemory_AllocateAndClear(sizeof(uint8_t) * length);
+ if (array == NULL) {
+ return NULL;
+ }
+ }
+ PARCByteArray *result = parcObject_CreateInstance(PARCByteArray);
+
+ if (result != NULL) {
+ result->array = array;
+ result->length = length;
+ result->freeFunction = parcMemory_DeallocateImpl;
+ return result;
+ } else {
+ parcMemory_Deallocate(&array);
+ }
+ return NULL;
+}
+
+PARCByteArray *
+parcByteArray_Wrap(const size_t length, uint8_t array[length])
+{
+ if (array != NULL) {
+ PARCByteArray *result = parcObject_CreateInstance(PARCByteArray);
+ if (result != NULL) {
+ result->array = array;
+ result->length = length;
+ result->freeFunction = NULL;
+ return result;
+ }
+ }
+ return NULL;
+}
+
+parcObject_ImplementAcquire(parcByteArray, PARCByteArray);
+
+parcObject_ImplementRelease(parcByteArray, PARCByteArray);
+
+PARCByteArray *
+parcByteArray_Copy(const PARCByteArray *original)
+{
+ parcByteArray_OptionalAssertValid(original);
+
+ PARCByteArray *result = NULL;
+
+ if (original != NULL) {
+ result = parcByteArray_Allocate(original->length);
+ memcpy(result->array, original->array, result->length);
+ }
+
+ return result;
+}
+
+size_t
+parcByteArray_Capacity(const PARCByteArray *byteArray)
+{
+ parcByteArray_OptionalAssertValid(byteArray);
+ return byteArray->length;
+}
+
+PARCByteArray *
+parcByteArray_PutByte(PARCByteArray *result, size_t index, uint8_t byte)
+{
+ parcByteArray_OptionalAssertValid(result);
+ _trapIfOutOfBounds(result, index);
+
+ result->array[index] = byte;
+ return result;
+}
+
+uint8_t
+parcByteArray_GetByte(const PARCByteArray *array, size_t index)
+{
+ parcByteArray_OptionalAssertValid(array);
+ _trapIfOutOfBounds(array, index);
+
+ return array->array[index];
+}
+
+uint8_t *
+parcByteArray_Array(const PARCByteArray *byteArray)
+{
+ parcByteArray_OptionalAssertValid(byteArray);
+ return byteArray->array;
+}
+
+uint8_t *
+parcByteArray_AddressOfIndex(const PARCByteArray *array, const size_t index)
+{
+ parcByteArray_OptionalAssertValid(array);
+ _trapIfOutOfBounds(array, index);
+
+ return &array->array[index];
+}
+
+int
+parcByteArray_Compare(const PARCByteArray *x, const PARCByteArray *y)
+{
+ if (x == y) {
+ return 0;
+ }
+
+ if (x == NULL) {
+ return -1;
+ }
+
+ if (y == NULL) {
+ return +1;
+ }
+
+ if (parcByteArray_Capacity(x) > parcByteArray_Capacity(y)) {
+ return +1;
+ }
+ if (parcByteArray_Capacity(x) < parcByteArray_Capacity(y)) {
+ return -1;
+ }
+
+ return memcmp(x->array, y->array, parcByteArray_Capacity(x));
+}
+
+PARCByteArray *
+parcByteArray_PutBytes(PARCByteArray *result, size_t offset, size_t length, const uint8_t source[length])
+{
+ parcByteArray_OptionalAssertValid(result);
+ trapOutOfBoundsIf(offset > result->length,
+ "The offset (%zd) exeeds the length (%zd) of the PARCByteArray.", offset, result->length);
+
+ size_t available = result->length - offset;
+
+ trapOutOfBoundsIf(length > available, "%zd available bytes, %zd required.", available, length);
+
+ memcpy(&result->array[offset], source, length);
+ return result;
+}
+
+PARCByteArray *
+parcByteArray_GetBytes(const PARCByteArray *result, size_t offset, size_t length, uint8_t array[length])
+{
+ parcByteArray_OptionalAssertValid(result);
+
+ size_t available = result->length - offset;
+
+ trapOutOfBoundsIf(length > available, "parcByteArray_CopyOut %zd available bytes, %zd required", available, length);
+
+ memcpy(array, &result->array[offset], length);
+ return (PARCByteArray *) result;
+}
+
+PARCByteArray *
+parcByteArray_ArrayCopy(PARCByteArray *destination, size_t destOffset, const PARCByteArray *source, size_t srcOffset, size_t length)
+{
+ parcByteArray_OptionalAssertValid(destination);
+ parcByteArray_OptionalAssertValid(source);
+
+ memcpy(&destination->array[destOffset], &source->array[srcOffset], length);
+ return destination;
+}
+
+bool
+parcByteArray_Equals(const PARCByteArray *a, const PARCByteArray *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ if (a->length == b->length) {
+ return memcmp(a->array, b->array, a->length) == 0;
+ }
+ return false;
+}
+
+static void
+_parcByteArray_PrettyPrintLine(const unsigned char *memory, size_t offset, size_t length)
+{
+ int bytesPerLine = 16;
+ char accumulator[bytesPerLine + 1];
+ memset(accumulator, ' ', bytesPerLine);
+ accumulator[bytesPerLine] = 0;
+
+ printf("%5zd: ", offset);
+
+ for (int i = 0; i < bytesPerLine; i++) {
+ if (offset + i >= length) {
+ printf(" ");
+ accumulator[i] = ' ';
+ } else {
+ char c = memory[offset + i];
+ printf("0x%02x, ", c & 0xFF);
+ if (isprint(c)) {
+ accumulator[i] = c;
+ } else {
+ accumulator[i] = '.';
+ }
+ }
+ }
+ printf(" %s\n", accumulator);
+}
+
+void
+parcByteArray_Display(const PARCByteArray *array, int indentation)
+{
+ int bytesPerLine = 16;
+
+ if (array->array == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCByteArray@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCByteArray@%p = [0,%zd)", (void *) array, array->length);
+
+ for (size_t offset = 0; offset < array->length; offset += bytesPerLine) {
+ _parcByteArray_PrettyPrintLine(array->array, offset, array->length);
+ }
+ }
+}
+
+PARCHashCode
+parcByteArray_HashCode(const PARCByteArray *array)
+{
+ parcByteArray_OptionalAssertValid(array);
+ return parcHashCode_Hash(array->array, array->length);
+}
diff --git a/libparc/parc/algol/parc_ByteArray.h b/libparc/parc/algol/parc_ByteArray.h
new file mode 100644
index 00000000..98cc970a
--- /dev/null
+++ b/libparc/parc/algol/parc_ByteArray.h
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_ByteArray.h
+ * @ingroup memory
+ * @brief A simple reference counted unsigned byte array.
+ *
+ * @htmlonly
+ * <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1" viewBox="48 74 304 68" width="304pt" height="68pt">
+ * <defs>
+ * <font-face font-family="Helvetica Neue" font-size="10" panose-1="2 0 5 3 0 0 0 2 0 4" units-per-em="1000" underline-position="-100" underline-thickness="50" slope="0" x-height="517" cap-height="714" ascent="951.99585" descent="-212.99744" font-weight="500">
+ * <font-face-src>
+ * <font-face-name name="HelveticaNeue"/>
+ * </font-face-src>
+ * </font-face>
+ * <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black">
+ * <g>
+ * <path d="M 8 0 L 0 -3 L 0 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+ * </g>
+ * </marker>
+ * </defs>
+ * <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+ * <title>icon_512x512</title>
+ * <rect fill="white" width="512" height="512"/>
+ * <g>
+ * <title>Layer 1</title>
+ * <text transform="translate(271 88.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".185" y="10" textLength="39.63">Capacity</tspan>
+ * </text>
+ * <text transform="translate(83 88.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".245" y="10" textLength="23.51">Array</tspan>
+ * </text>
+ * <path d="M 78 96.483333 C 73.6671 96.98884 67.757544 94.49623 65 98 C 63.49089 99.917494 62.925312 103.63153 62.52875 107.66717" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <rect x="59" y="118" width="281" height="13" fill="white"/>
+ * <rect x="59" y="118" width="281" height="13" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 316 97.11628 C 321.9994 97.744123 330.42197 95.601626 334 99 C 335.8631 100.769544 336.41326 104.04195 336.67595 107.643264" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * </g>
+ * </g>
+ * </svg>
+ * @endhtmlonly
+ *
+ * `PARCByteArray` is a simple reference counted array of `uint8_t` values.
+ * Instances of `PARCByteArray` are created either by dynamically allocating the byte array,
+ * via `parcByteArray_Allocate()`,
+ * or by wrapping a static `uint8_t` array,
+ * via `parcByteArray_Wrap()`.
+ *
+ * New references to an existing instance of `PARCByteArray` are created via `parcByteArray_Acquire()`.
+ *
+ * A `PARCByteArray` reference is released via `parcByteArray_Release`.
+ * Only the last invocation will deallocated the `PARCByteArray`.
+ * If the `PARCByteArray` references dynamically allocated memory,
+ * that memory is freed with the `PARCByteArray` when the last reference is released.
+ *
+ */
+#ifndef libparc_parc_ByteArray_h
+#define libparc_parc_ByteArray_h
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_byte_array;
+/**
+ *
+ * @see {@link parcByteArray_Allocate}
+ * @see {@link parcByteArray_Wrap}
+ */
+typedef struct parc_byte_array PARCByteArray;
+
+#include <parc/algol/parc_HashCode.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcByteArray_OptionalAssertValid(_instance_)
+#else
+# define parcByteArray_OptionalAssertValid(_instance_) parcByteArray_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `PARCByteArray` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a `PARCByteArray` instance.
+ */
+void parcByteArray_AssertValid(const PARCByteArray *instance);
+
+/**
+ * Determine if an instance of `PARCByteArray` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a `PARCByteArray` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ */
+bool parcByteArray_IsValid(const PARCByteArray *instance);
+
+/**
+ * Dynamically allocate a `PARCByteArray` of a specific capacity.
+ *
+ * @param [in] capacity The number of bytes in the byte array.
+ *
+ * @return A pointer to an allocated `PARCByteArray` instance which must be released via {@link parcByteArray_Release()}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *byteArray = parcByteArray_Allocate(100);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Release
+ */
+PARCByteArray *parcByteArray_Allocate(const size_t capacity);
+
+/**
+ * Wrap existing memory in a {@link PARCByteArray}.
+ *
+ * As in all `Wrap` functions, a copy of the memory is not made.
+ * Be sure to only wrap memory that is either global,
+ * or used within on stack-frame or functional block.
+ * Otherwise, corruption is likly to occur.
+ *
+ * @param [in] capacity The maximum capacity of the backing array.
+ * @param [in] array A pointer to the backing array.
+ *
+ * @return A pointer to an allocated `PARCByteArray` instance which must be released via {@link parcByteArray_Release()}.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_Wrap(size_t capacity, uint8_t *array);
+
+/**
+ * Returns the pointer to the `uint8_t` array that backs this `PARCByteArray`.
+ *
+ * Modifications to the given `PARCByteArray` content will cause the returned array's content to be modified, and vice versa.
+ *
+ * The reference count for the given `PARCByteArray` is not modified.
+ *
+ * <b>Use with caution.</b>
+ *
+ * @param [in] byteArray Pointer to a `PARCByteArray` instance from which the underlying array is extracted.
+ *
+ * @return The pointer to the `uint8_t` array that backs this `PARCByteArray`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * uint8_t *raw = parcByteArray_Array(byteArray);
+ * // updates on the raw array (pointer) are seen in the byteArray instance
+ * // use with caution
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+uint8_t *parcByteArray_Array(const PARCByteArray *byteArray);
+
+/**
+ * Increase the number of references to a `PARCByteArray`.
+ *
+ * Note that a new `PARCByteArray` is not created,
+ * only that the given `PARCByteArray` reference count is incremented.
+ * Discard the reference by invoking {@link parcByteArray_Release}.
+ *
+ * @param [in] instance A pointer to the original `PARCByteArray` instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *x = parcByteArray_Allocate(10);
+ *
+ * PARCByteArray *x_2 = parcByteArray_Acquire(x);
+ *
+ * parcByteArray_Release(&x);
+ * parcByteArray_Release(&x_2);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Release
+ */
+PARCByteArray *parcByteArray_Acquire(const PARCByteArray *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] byteArrayPtr A pointer to a pointer to the instance of `PARCByteArray` to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *x = parcByteArray_Acquire(...);
+ *
+ * parcByteArray_Release(&x);
+ * }
+ * @endcode
+ */
+void parcByteArray_Release(PARCByteArray **byteArrayPtr);
+
+/**
+ * Put an `uint8_t` value into the byte array at the given index.
+ *
+ * The value of @p index must be greater than or equal to 0, and less than the capacity.
+ *
+ * @param [in,out] result A pointer to the instance of `PARCByteArray` that will receive the data.
+ * @param [in] index The index at which the byte will be inserted.
+ * @param [in] byte The byte to be inserted into the array.
+ *
+ * @return The `PARCByteArray` that receive the data.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * parcByteArray_PutByte(byteArray, 5, 123);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_PutByte(PARCByteArray *result, size_t index, uint8_t byte);
+
+/**
+ * Get the value at a specific index from the given `PARCByteArray`.
+ *
+ * @param [in] result The instance of `PARCByteArray` that will produce the data.
+ * @param [in] index The index from which the byte will be retrieved.
+ *
+ * @return The value at a specific index from the given `PARCByteArray`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * parcByteArray_PutByte(byteArray, 5, 123);
+ *
+ * parcByteArray_GetByte(byteArray, 5);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+uint8_t parcByteArray_GetByte(const PARCByteArray *result, size_t index);
+
+/**
+ * Compares instance a with instance b for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as instance a is less than, equal to, or greater than instance b.
+ *
+ * @param [in] a A pointer to a `PARCByteArray` instance 'a'.
+ * @param [in] b A pointer to another `PARCByteArray` instance 'b'.
+ *
+ * @return <0 Instance a is less then instance b.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray1 = parcByteArray_Wrap(array, 10);
+ * PARCByteArray *byteArray2 = parcByteArray_Wrap(array, 10);
+ *
+ * if (parcByteArray_Compare(byteArray1, byteArray2) == 0) {
+ * printf("Equal\n");
+ * }
+ *
+ * parcByteArray_Release(&byteArray1);
+ * parcByteArray_Release(&byteArray2);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Equal
+ */
+int parcByteArray_Compare(const PARCByteArray *a, const PARCByteArray *b);
+
+/**
+ * Copy data from an external array into a `PARCByteArray`.
+ *
+ * Provided that the underlying `PARCByteArray` is large enough,
+ * copy the bytes from the given `array` for `length` bytes.
+ *
+ * @param [in,out] result The `PARCByteArray` that will receive the data.
+ * @param [in] offset The offset into the `PARCByteArray` that will receive the data.
+ * @param [in] length The number of bytes to copy in.
+ * @param [in] source The uint8_t array containing the original data.
+ *
+ * @return The given `PARCByteArray` pointer
+ *
+ * @throws SIGABRT `trapOutOfBounds` if the underlying `PARCByteArray` is not large enough
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ * uint8_t inner[3];
+ * inner[0] = 0xFF;
+ * inner[1] = 0xFF;
+ * inner[2] = 0xFF;
+ *
+ * parcByteArray_PutBytes(byteArray, 1, 3, inner);
+ * // Bytes 1,2,3 of byteArray will be 0xFF (offset was 1, not 0)
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_PutBytes(PARCByteArray *result, size_t offset, size_t length, const uint8_t *source);
+
+/**
+ * Copy data from a `PARCByteArray` into an external array.
+ *
+ * Provided that the underlying `PARCByteArray` has at least `length` bytes
+ * copy the bytes from the `PARCByteArray` into the given `array`.
+ *
+ * @param [in] source The `PARCByteArray` that will produce the data.
+ * @param [in] offset The offset into the `PARCByteArray` from which the data will be copied.
+ * @param [in] length The number of bytes to copy from the <code>PARCByteArray</code> into @p destination.
+ * @param [in] destination The `uint8_t` array That will contain the data.
+ *
+ * @return The given `PARCByteArray` @p source pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * uint8_t inner[3];
+ * parcByteArray_GetBytes(byteArray, 0, 3, inner);
+ * // inner will contain a copy of bytes 0,1,2 from the byteArray
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_GetBytes(const PARCByteArray *source, size_t offset, size_t length, uint8_t *destination);
+
+
+/**
+ * Copy a portion of one `PARCByteArray` into another.
+ *
+ * The sum of (destination/source) offset and length must be within the bounds of the
+ * respective (destination/source) `PARCByteArray` instances.
+ *
+ * @param [in,out] destination Pointer to the destination `PARCByteArray` instance.
+ * @param [in] destOffset Offset within the destination `PARCByteArray` instance.
+ * @param [in] source Pointer to the source `PARCByteArray` instance.
+ * @param [in] srcOffset Offset within the source `PARCByteArray` instance.
+ * @param [in] length Number of bytes to copy from the source to the destination.
+ *
+ * @return PARCByteArray* A pointer to the destination.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array1[10];
+ * PARCByteArray *byteArray1 = parcByteArray_Wrap(array1, 10);
+ * uint8_t array2[3];
+ * array2[0] = 0xAA;
+ * array2[1] = 0xBB;
+ * array2[2] = 0xCC;
+ * PARCByteArray *byteArray2 = parcByteArray_Wrap(array2, 3);
+ *
+ * parcByteArray_ArrayCopy(byteArray1, 0, byteArray2, 0, 3);
+ * // the first three bytes of byteArray1 will now be 0xAA,0xBB,0xCC
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_ArrayCopy(PARCByteArray *destination, size_t destOffset, const PARCByteArray *source, size_t srcOffset, size_t length);
+
+/**
+ * Get the capacity of a `PARCByteArray`.
+ *
+ * The `PARCByteArray`'s capacity is the number of bytes stored in the backing store of a `PARCByteArray`.
+ *
+ * @param [in] byteArray Pointer to the `PARCByteArray` instance being examined.
+ *
+ * @return The capacity of a `PARCByteArray`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * size_t capacity = parcByteArray_Capacity(byteArray);
+ * }
+ * @endcode
+ */
+size_t parcByteArray_Capacity(const PARCByteArray *byteArray);
+
+/**
+ * Create a copy of an existing `PARCByteArray`.
+ *
+ * The copy is equal to, but shares nothing in common with, the original `PARCByteArray`
+ *
+ * @param [in] original A non-null pointer to the `PARCByteArray` to copy.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to the new `PARCByteArray` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ * PARCByteArray *copy = parcByteArray_Copy(byteArray);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Allocate
+ * @see parcByteArray_Wrap
+ */
+PARCByteArray *parcByteArray_Copy(const PARCByteArray *original);
+
+/**
+ * Determine if two `PARCByteArray` instances are equal.
+ *
+ * Two `PARCByteArray` instances are equal if, and only if,
+ * * They have the same number of elements, and
+ * * The two sequences of remaining elements are pointwise equal.
+ *
+ * The following equivalence relations on non-null `PARCByteArray` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcByteArray_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcByteArray_Equals(x, y)` must return true if and only if
+ * `parcByteArray_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcByteArray_Equals(x, y)` returns true and
+ * `parcByteArray_Equals(y, z)` returns true,
+ * then `parcByteArray_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcByteArray_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcByteArray_Equals(x, NULL)` must return false.
+ *
+ * @param [in] a A pointer to a `PARCByteArray` instance.
+ * @param [in] b A pointer to a `PARCByteArray` instance.
+ *
+ * @return true if the two `PARCByteArray` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray1 = parcByteArray_Wrap(array, 10);
+ * PARCByteArray *byteArray2 = parcByteArray_Wrap(array, 10);
+ *
+ * if (parcByteArray_Equals(byteArray1, byteArray2)) {
+ * printf("Equal\n");
+ * } else {
+ * printf("NOT Equal\n");
+ * }
+ *
+ * parcByteArray_Release(&byteArray1);
+ * parcByteArray_Release(&byteArray2);
+ * }
+ * @endcode
+ */
+bool parcByteArray_Equals(const PARCByteArray *a, const PARCByteArray *b);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the {@link parcByteArray_HashCode} function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcByteArray_Equals}
+ * comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcByteArray_Equals} method,
+ * then calling the {@link parcByteArray_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the {@link parcByteArray_Equals} function,
+ * then calling the {@link parcByteArray_HashCode}
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] array A pointer to the `PARCByteArray` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *array = parcByteArray_Allocate(10);
+ * uint32_t hashValue = parcByteArray_HashCode(array);
+ * parcByteArray_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_HashCode
+ */
+PARCHashCode parcByteArray_HashCode(const PARCByteArray *array);
+
+/**
+ * Return the memory address as a `uint8_t *` to the location specified by `index`.
+ *
+ * @param [in] array A pointer to the `PARCByteArray` instance.
+ * @param [in] index The index of the address.
+ *
+ * @return A pointer to the location offset by index bytes within the array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *byteArray = parcByteArray_Allocate(10);
+ * uint8_t *offsetAddress = parcByteArray_AddressOfIndex(byteArray, 4);
+ * // offsetAddress now points to the array at offset 4 within byteArray
+ * }
+ * @endcode
+ */
+uint8_t *parcByteArray_AddressOfIndex(const PARCByteArray *array, size_t index);
+
+/**
+ * Pretty print the given `PARCByteArray` instance.
+ *
+ * @param [in] indentation The amount of indentation to prefix each line of output
+ * @param [in] array The `PARCByteArray` instance to be printed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *byteArray = parcByteArray_Allocate(10);
+ * parcByteArray_Display(byteArray, 0);
+ * }
+ * @endcode
+ */
+void parcByteArray_Display(const PARCByteArray *array, int indentation);
+#endif // libparc_parc_ByteArray_h
diff --git a/libparc/parc/algol/parc_CMacro.h b/libparc/parc/algol/parc_CMacro.h
new file mode 100644
index 00000000..a47129ea
--- /dev/null
+++ b/libparc/parc/algol/parc_CMacro.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_CMacro.h
+ * @ingroup Macro
+ * @brief Utility C-Macros
+ *
+ * CMacro contains a set of utility macros for doing complicated macro processing
+ *
+ */
+#ifndef libparc_parc_CMacro_h
+#define libparc_parc_CMacro_h
+
+/**
+ * parcCMacro_ThridParam expands to the "3rd" input parameter whatever that may be. It is a part
+ * of the c-macro trick for implement a macro If-Else switch. If the first argument expands
+ * to a comma then this macro expands to the second parameter, otherwise it expands to the 3rd parameter.
+ */
+#define parcCMacro_ThirdParam(A, B, C, ...) C
+
+/**
+ * parcCMacro_IfElse is a c-macro trick for implementing a macro If-Else switch.
+ * It uses parcCMacro_ThirdParam to select between A or B depending on whether __VA_ARGS__ expands to a comma.
+ */
+#define parcCMacro_IfElse(A, B, ...) parcCMacro_ThirdParam(__VA_ARGS__, A, B, NOOP)
+
+/** \cond */
+#define _parcCMacro_Cat_(A, B) A ## B
+/** \endcond */
+
+/**
+ * parcCMacro_Cat combines two strings into a single token.
+ */
+#define parcCMacro_Cat(A, B) _parcCMacro_Cat_(A, B)
+
+#endif //libparc_parc_CMacro_h
diff --git a/libparc/parc/algol/parc_Chunker.c b/libparc/parc/algol/parc_Chunker.c
new file mode 100755
index 00000000..b84ed05f
--- /dev/null
+++ b/libparc/parc/algol/parc_Chunker.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_Chunker.h>
+
+struct parc_chunker {
+ PARCObject *instance;
+ const PARCChunkerInterface *interface;
+};
+
+static void
+_destroy(PARCChunker **chunkerP)
+{
+ parcObject_Release(&(*chunkerP)->instance);
+}
+
+
+parcObject_ExtendPARCObject(PARCChunker, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(parcChunker, PARCChunker);
+parcObject_ImplementRelease(parcChunker, PARCChunker);
+
+PARCChunker *
+parcChunker_Create(PARCObject *instance, PARCChunkerInterface *interface)
+{
+ PARCChunker *chunker = parcObject_CreateInstance(PARCChunker);
+
+ if (chunker != NULL) {
+ chunker->instance = parcObject_Acquire(instance);
+ chunker->interface = interface;
+ }
+
+ return chunker;
+}
+
+PARCIterator *
+parcChunker_ForwardIterator(const PARCChunker *chunker)
+{
+ return (chunker->interface)->ForwardIterator(chunker->instance);
+}
+
+PARCIterator *
+parcChunker_ReverseIterator(const PARCChunker *chunker)
+{
+ return (chunker->interface)->ReverseIterator(chunker->instance);
+}
+
+size_t
+parcChunker_GetChunkSize(const PARCChunker *chunker)
+{
+ return (chunker->interface)->GetChunkSize(chunker->instance);
+}
diff --git a/libparc/parc/algol/parc_Chunker.h b/libparc/parc/algol/parc_Chunker.h
new file mode 100755
index 00000000..305acad7
--- /dev/null
+++ b/libparc/parc/algol/parc_Chunker.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Chunker.h
+ * @ingroup ContentObject
+ * @brief A Chunker is an object that breaks up a large piece of data from a `PARCBuffer`
+ * or a file and provides an iterator to walk over the chunks in sequential order.
+ *
+ */
+
+#ifndef libparc_parc_Chunker_h
+#define libparc_parc_Chunker_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_chunker;
+/**
+ * @typedef PARCChunker
+ * @brief The PARC Chunker
+ */
+typedef struct parc_chunker PARCChunker;
+
+typedef struct PARCChunkerInterface {
+ /**
+ * @see parcChunker_ForwardIterator
+ */
+ void *(*ForwardIterator)(const void *original);
+
+ /**
+ * @see parcChunker_ReverseIterator
+ */
+ void *(*ReverseIterator)(const void *original);
+
+ /**
+ * @see parcChunker_GetChunkSize
+ */
+ size_t (*GetChunkSize)(const void *original);
+} PARCChunkerInterface;
+
+/**
+ * Create a new chunker from the given concrete instance.
+ *
+ * @param [in] instance A `PARCChunker` instance.
+ * @param [in] interface The interface implementation of the chunker.
+ *
+ * @retval PARCChunker A newly allocated `PARCChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunkerBuffer *bufferChunker = parcBufferChunker_Create(dataToChunk, 32);
+ * PARCChunker *chunker = parcChunker_Create(bufferCunker, &PARCBufferChunkerAsChunker);
+ * }
+ */
+PARCChunker *parcChunker_Create(PARCObject *instance, PARCChunkerInterface *interface);
+
+/**
+ * Create a new chunker to segment data contained in a file.
+ *
+ * @param [in] fileName The name of a file from which to read.
+ * @param [in] chunkSize The size per chunk.
+ *
+ * @retval PARCChunker A newly allocated `PARCChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * char *bigFileName = "big_file.bin";
+ * PARCChunker *chunker = parcChunker_CreateFromBuffer(bigFileName, 32);
+ * }
+ */
+//PARCChunker *parcChunker_CreateFromFile(char *fileName, size_t maxDataSize);
+
+/**
+ * Increase the number of references to a `PARCChunker` instance.
+ *
+ * Note that new `PARCChunker` is not created,
+ * only that the given `PARCChunker` reference count is incremented.
+ * Discard the reference by invoking {@link parcChunker_Release}.
+ *
+ * @param [in] chunker A pointer to the original `PARCChunker`.
+ * @return The value of the input parameter @p chunker.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCChunker *original = ...
+ *
+ * PARCChunker *reference = parcChunker_Acquire(original);
+ *
+ * parcChunker_Release(&original);
+ * parcChunker_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcChunker_Release
+ */
+PARCChunker *parcChunker_Acquire(const PARCChunker *chunker);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] chunkerP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCChunker *chunker = parcChunker_Acquire(instance);
+ *
+ * parcChunker_Release(&chunker);
+ * }
+ * @endcode
+ */
+void parcChunker_Release(PARCChunker **chunkerP);
+
+/**
+ * Determine if two `PARCChunker` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCChunker` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcChunker_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcChunker_Equals(x, y)` must return true if and only if
+ * `parcChunker_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcChunker_Equals(x, y)` returns true and
+ * `parcChunker_Equals(y, z)` returns true,
+ * then `parcChunker_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcChunker_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcChunker_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param chunkerA A pointer to a `PARCChunker` instance.
+ * @param chunkerB A pointer to a `PARCChunker` instance.
+ * @return true if the two `PARCChunker` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunkerA = ...
+ * PARCChunker *chunkerB = ...
+ *
+ * bool equals = parcChunker_Equals(chunkerA, chunkerB);
+ * }
+ * @endcode
+ */
+bool parcChunker_Equals(const PARCChunker *chunkerA, const PARCChunker *chunkerB);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = ...
+ *
+ * PARCIterator *itr = parcChunker_ForwardIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcChunker_ForwardIterator(const PARCChunker *chunker);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunker = ...
+ *
+ * PARCIterator *itr = parcChunker_ReverseIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcChunker_ReverseIterator(const PARCChunker *chunker);
+
+/**
+ * Get the chunk size of a `PARCChunker.`
+ *
+ * @param [in] chunker A `PARCChunker` instance.
+ *
+ * @return the chunk size
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunker = ...
+ *
+ * size_t chunkSize = parcChunker_GetChunkSize(chunker);
+ * }
+ * @endcode
+ */
+size_t parcChunker_GetChunkSize(const PARCChunker *chunker);
+#endif // libparc_parc_Chunker_h
diff --git a/libparc/parc/algol/parc_Clock.c b/libparc/parc/algol/parc_Clock.c
new file mode 100755
index 00000000..95cf74bc
--- /dev/null
+++ b/libparc/parc/algol/parc_Clock.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <time.h>
+#include <parc/algol/parc_Clock.h>
+
+#if __APPLE__
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+#endif
+
+// These are used by the counter Clock
+#include <parc/algol/parc_AtomicInteger.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+// ----
+
+typedef struct counter_clock {
+ uint64_t counter;
+} _CounterClock;
+
+parcObject_ExtendPARCObject(_CounterClock, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+static parcObject_ImplementAcquire(_counterClock, _CounterClock);
+
+static PARCClock *
+_counterClock_AcquireInterface(const PARCClock *clock)
+{
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+ _counterClock_Acquire(cc);
+ return (PARCClock *) clock;
+}
+
+static void
+_counterClock_ReleaseInterface(PARCClock **clockPtr)
+{
+ PARCClock *clock = *clockPtr;
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+
+ PARCReferenceCount refcount = parcObject_Release((void **) &cc);
+ if (refcount == 0) {
+ parcMemory_Deallocate((void **) clockPtr);
+ } else {
+ *clockPtr = NULL;
+ }
+}
+
+static void
+_counterClock_GetTimeval(const PARCClock *clock, struct timeval *output)
+{
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+ uint64_t value = parcAtomicInteger_Uint64Increment(&cc->counter);
+
+ // put 19 bits in the micro-seconds so it is never larger than 1E+6
+ output->tv_sec = value >> 19;
+ output->tv_usec = value & 0x7FFFF;
+}
+
+static uint64_t
+_counterClock_GetTime(const PARCClock *clock)
+{
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+ return parcAtomicInteger_Uint64Increment(&cc->counter);
+}
+
+PARCClock *
+parcClock_Counter(void)
+{
+ _CounterClock *cc = parcObject_CreateInstance(_CounterClock);
+ cc->counter = 0;
+
+ PARCClock *clock = parcMemory_Allocate(sizeof(PARCClock));
+ clock->closure = cc;
+ clock->acquire = _counterClock_AcquireInterface;
+ clock->release = _counterClock_ReleaseInterface;
+ clock->getTime = _counterClock_GetTime;
+ clock->getTimeval = _counterClock_GetTimeval;
+ return clock;
+}
+
+// ===========
+// Wallclock
+
+static void
+_wallclock_GetTimeval(const PARCClock *dummy __attribute__((unused)), struct timeval *output)
+{
+#if __linux__
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ output->tv_sec = ts.tv_sec;
+ output->tv_usec = ts.tv_nsec / 1000;
+#else
+ clock_serv_t clockService;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clockService);
+ clock_get_time(clockService, &mts);
+ mach_port_deallocate(mach_task_self(), clockService);
+
+ output->tv_sec = mts.tv_sec;
+ output->tv_usec = mts.tv_nsec / 1000;
+#endif
+}
+
+static uint64_t
+_wallclock_GetTime(const PARCClock *clock)
+{
+ struct timeval tv;
+ _wallclock_GetTimeval(clock, &tv);
+ uint64_t t = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+ return t;
+}
+
+
+static PARCClock *
+_wallclock_Acquire(const PARCClock *clock)
+{
+ return (PARCClock *) clock;
+}
+
+static void
+_wallclock_Release(PARCClock **clockPtr)
+{
+ *clockPtr = NULL;
+}
+
+static PARCClock _wallclock = {
+ .closure = NULL,
+ .getTime = _wallclock_GetTime,
+ .getTimeval = _wallclock_GetTimeval,
+ .acquire = _wallclock_Acquire,
+ .release = _wallclock_Release
+};
+
+PARCClock *
+parcClock_Wallclock(void)
+{
+ return &_wallclock;
+}
+
+
+// ==========================
+// Monotonic clock
+
+static void
+_monoclock_GetTimeval(const PARCClock *dummy __attribute__((unused)), struct timeval *output)
+{
+#if __linux__
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ output->tv_sec = ts.tv_sec;
+ output->tv_usec = ts.tv_nsec / 1000;
+#else
+ clock_serv_t clockService;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clockService);
+ clock_get_time(clockService, &mts);
+ mach_port_deallocate(mach_task_self(), clockService);
+
+ output->tv_sec = mts.tv_sec;
+ output->tv_usec = mts.tv_nsec / 1000;
+#endif
+}
+
+static uint64_t
+_monoclock_GetTime(const PARCClock *clock)
+{
+ struct timeval tv;
+ _monoclock_GetTimeval(clock, &tv);
+ uint64_t t = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+ return t;
+}
+
+static PARCClock *
+_monoclock_Acquire(const PARCClock *clock)
+{
+ return (PARCClock *) clock;
+}
+
+static void
+_monoclock_Release(PARCClock **clockPtr)
+{
+ *clockPtr = NULL;
+}
+
+static PARCClock _monoclock = {
+ .closure = NULL,
+ .getTime = _monoclock_GetTime,
+ .getTimeval = _monoclock_GetTimeval,
+ .acquire = _monoclock_Acquire,
+ .release = _monoclock_Release
+};
+
+PARCClock *
+parcClock_Monotonic(void)
+{
+ return &_monoclock;
+}
+
+// ===========================
+// Facade API
+
+uint64_t
+parcClock_GetTime(const PARCClock *clock)
+{
+ return clock->getTime(clock);
+}
+
+void
+parcClock_GetTimeval(const PARCClock *clock, struct timeval *output)
+{
+ clock->getTimeval(clock, output);
+}
+
+PARCClock *
+parcClock_Acquire(const PARCClock *clock)
+{
+ return clock->acquire(clock);
+}
+
+void
+parcClock_Release(PARCClock **clockPtr)
+{
+ (*clockPtr)->release(clockPtr);
+}
+
diff --git a/libparc/parc/algol/parc_Clock.h b/libparc/parc/algol/parc_Clock.h
new file mode 100755
index 00000000..35c77fd7
--- /dev/null
+++ b/libparc/parc/algol/parc_Clock.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Clock.h
+ * @ingroup datastructures
+ * @brief Generic API to a clock
+ *
+ * Interface over clock providers. We provide two system clocks, a Wallclock that tracks the
+ * real time clock and a monotonic clock that will not skew or go backwards.
+ * @see parcClock_Monotonic()
+ * and
+ * @see parcClock_Wallclock()
+ * Also provided is a counting clock.
+ * @see parcClock_Counter()
+ *
+ * Below is a complete example of a simple custom clock that implements an atomic counter for
+ * the time. Each call to getTime or getTimeval will increment the counter. This clock is
+ * available as parcClock_Counter().
+ *
+ * @code
+ * typedef struct counter_clock {
+ * uint64_t counter;
+ * } _CounterClock;
+ *
+ * parcObject_ExtendPARCObject(_CounterClock, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ * static parcObject_ImplementAcquire(_counterClock, _CounterClock);
+ *
+ * static PARCClock *
+ * _counterClock_AcquireInterface(const PARCClock *clock)
+ * {
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ * _counterClock_Acquire(cc);
+ * return (PARCClock *) clock;
+ * }
+ *
+ * static void
+ * _counterClock_ReleaseInterface(PARCClock **clockPtr)
+ * {
+ * PARCClock *clock = *clockPtr;
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ *
+ * PARCReferenceCount refcount = parcObject_Release((void **) &cc);
+ * if (refcount == 0) {
+ * parcMemory_Deallocate((void **) clockPtr);
+ * } else {
+ * *clockPtr = NULL;
+ * }
+ * }
+ *
+ * static void
+ * _counterClock_GetTimeval(const PARCClock *clock, struct timeval *output)
+ * {
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ * uint64_t value = parcAtomicInteger_Uint64Increment(&cc->counter);
+ * // put 19 bits in the micro-seconds so it is never larger than 1E+6
+ * output->tv_sec = value >> 19;
+ * output->tv_usec = value & 0x7FFFF;
+ * }
+ *
+ * static uint64_t
+ * _counterClock_GetTime(const PARCClock *clock)
+ * {
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ * return parcAtomicInteger_Uint64Increment(&cc->counter);
+ * }
+ *
+ * PARCClock *
+ * parcClock_Counter(void)
+ * {
+ * _CounterClock *cc = parcObject_CreateInstance(_CounterClock);
+ * cc->counter = 0;
+ *
+ * PARCClock *clock = parcMemory_Allocate(sizeof(PARCClock));
+ * clock->closure = cc;
+ * clock->acquire = _counterClock_AcquireInterface;
+ * clock->release = _counterClock_ReleaseInterface;
+ * clock->getTime = _counterClock_GetTime;
+ * clock->getTimeval = _counterClock_GetTimeval;
+ * return clock;
+ * }
+ * @encode
+ *
+ */
+
+#ifndef PARC_parc_Clock_h
+#define PARC_parc_Clock_h
+
+#include <inttypes.h>
+#include <sys/time.h>
+
+struct parc_clock;
+typedef struct parc_clock PARCClock;
+
+struct parc_clock {
+ /**
+ * Opaque parameter set by the clock provider
+ */
+ void *closure;
+
+ /**
+ * Gets the clock time
+ *
+ * The resolution and epoch of the clock are determined by the clock provider
+ *
+ * @param [in] clock An allocated PARCClock
+ *
+ * @retval number The clock's time as a uint64_t
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Monotonic();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+ uint64_t (*getTime)(const PARCClock *clock);
+
+ /**
+ * Gets the clock time as a struct timeval
+ *
+ * The resolution and epoch of the clock are determined by the clock provider.
+ * There may be an arbitrary mapping to the struct timeval as per the clock
+ * provider, so the units of 'seconds' and 'micro seconds' need to be interpreted
+ * as per the clock provider.
+ *
+ * @param [in] clock An allocated PARCClock
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void (*getTimeval)(const PARCClock *clock, struct timeval *output);
+
+ /**
+ * Increase the number of references to a `PARCClock`.
+ *
+ * Note that new `PARCClock` is not created,
+ * only that the given `PARCClock` reference count is incremented.
+ * Discard the reference by invoking `parcClock_Release`.
+ *
+ * @param [in] clock A pointer to a `PARCClock` instance.
+ *
+ * @return The input `PARCClock` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+ PARCClock * (*acquire)(const PARCClock *clock);
+
+ /**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] clockPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+
+ void (*release)(PARCClock **clockPtr);
+};
+
+/**
+ * A clock provider for the wall clock time
+ *
+ * This will use clock_gettime(CLOCK_REALTIME_COARSE) on linux or
+ * host_get_clock_service with CALENDAR_CLOCK on Mac
+ *
+ * @retval non-null An allocated PARCClock, which must be released via parcClock_Release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Wallclock();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Wallclock(void);
+
+/**
+ * A monotonic clock that will not normally adjust for time changes
+ *
+ * On linux, this uses the CLOCK_MONOTONIC_RAW. On Darwin, it uses
+ * the SYSTEM_CLOCK from <mach/mach_time.h>.
+ *
+ * @retval non-null An allocated PARCClock, which must be released via parcClock_Release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Monotonic();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Monotonic(void);
+
+
+/**
+ * The counter clock begins at 0 and increments for every call to getTime or getTimeval
+ *
+ * Each allocated counter clock will begin at zero. Copies made via parcClock_Acquire() will
+ * share the same counter and use atomic updates.
+ *
+ * getTime() will return the counter.
+ *
+ * getTimeval() will return the lower 19 bits in tv_usec (so it does not overflow the concept
+ * of micro-second) and the upper 45 bits are in tv_sec. On some platforms, that may overflow.
+ *
+ * @retval non-null An allocated PARCClock, which must be released via parcClock_Release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Counter(void);
+
+/**
+ * Returns the clock provider's idea of the current time as a uint64
+ *
+ * Returns the clock provider's idea of the current time, which may or
+ * may not be a wall clock time.
+ *
+ * @param [in] clock A clock provider
+ *
+ * @retval number The current time (depends on provider)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+uint64_t parcClock_GetTime(const PARCClock *clock);
+
+/**
+ * Returns the clock provider's idea of the current time as a timeval
+ *
+ * Returns the clock provider's idea of the current time, which may or
+ * may not be a wall clock time.
+ *
+ * @param [in] clock A clock provider
+ * @param [in] output The structure to fill in with the current time
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval t;
+ * PARCClock *clock = parcClock_Counter();
+ * parcClock_GetTimeval(clock, &t);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+void parcClock_GetTimeval(const PARCClock *clock, struct timeval *output);
+
+/**
+ * Increase the number of references to a `PARCClock`.
+ *
+ * Note that new `PARCClock` is not created,
+ * only that the given `PARCClock` reference count is incremented.
+ * Discard the reference by invoking `parcClock_Release`.
+ *
+ * @param [in] clock A pointer to a `PARCClock` instance.
+ *
+ * @return The input `PARCClock` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Acquire(const PARCClock *clock);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] clockPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+void parcClock_Release(PARCClock **clockPtr);
+#endif // PARC_parc_Clock_h
diff --git a/libparc/parc/algol/parc_Collection.h b/libparc/parc/algol/parc_Collection.h
new file mode 100755
index 00000000..87deff12
--- /dev/null
+++ b/libparc/parc/algol/parc_Collection.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Collection.h
+ * @ingroup datastructures
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#ifndef libparc_parc_Collection_h
+#define libparc_parc_Collection_h
+
+struct parc_collection;
+typedef struct parc_collection PARCCollection;
+#endif // libparc_parc_Collection_h
diff --git a/libparc/parc/algol/parc_Deque.c b/libparc/parc/algol/parc_Deque.c
new file mode 100644
index 00000000..4793b032
--- /dev/null
+++ b/libparc/parc/algol/parc_Deque.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include <parc/algol/parc_Deque.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+PARCListInterface *PARCDequeAsPARCList = &(PARCListInterface) {
+ .Add = (bool (*)(void *, void *))parcDeque_Append,
+ .AddAtIndex = (void (*)(void *, int index, void *))NULL,
+ .AddCollection = (bool (*)(void *, PARCCollection *))NULL,
+ .AddCollectionAtIndex = (bool (*)(void *, int index, PARCCollection *))NULL,
+ .Clear = (void (*)(void *))NULL,
+ .Contains = (bool (*)(const void *, const PARCObject *))NULL,
+ .ContainsCollection = (bool (*)(const void *, const PARCCollection *))NULL,
+ .Copy = (void * (*)(const PARCList *))parcDeque_Copy,
+ .Destroy = (void (*)(void **))parcDeque_Release,
+ .Equals = (bool (*)(const void *, const void *))parcDeque_Equals,
+ .GetAtIndex = (void * (*)(const void *, size_t))parcDeque_GetAtIndex,
+ .HashCode = (PARCHashCode (*)(const void *))NULL,
+ .IndexOf = (size_t (*)(const void *, const PARCObject *element))NULL,
+ .IsEmpty = (bool (*)(const void *))parcDeque_IsEmpty,
+ .LastIndexOf = (size_t (*)(void *, const PARCObject *element))NULL,
+ .Remove = (bool (*)(void *, const PARCObject *element))NULL,
+ .RemoveAtIndex = (void * (*)(PARCList *, size_t))NULL,
+ .RemoveCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .RetainCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .SetAtIndex = (void * (*)(void *, size_t index, void *))NULL,
+ .Size = (size_t (*)(const void *))parcDeque_Size,
+ .SubList = (PARCList * (*)(const void *, size_t, size_t))NULL,
+ .ToArray = (void** (*)(const void *))NULL,
+};
+
+struct parc_deque_node {
+ void *element;
+ struct parc_deque_node *previous;
+ struct parc_deque_node *next;
+};
+
+struct parc_deque {
+ PARCObjectDescriptor object;
+ struct parc_deque_node *head;
+ struct parc_deque_node *tail;
+ size_t size;
+};
+
+static void *
+_defaultElementCopy(const void *x)
+{
+ return (void *) x;
+}
+
+static bool
+_defaultElementEquals(const void *x, const void *y)
+{
+ return (x == y);
+}
+
+static inline struct parc_deque_node *
+_parcDequeNode_Create(void *element, struct parc_deque_node *previous, struct parc_deque_node *next)
+{
+ struct parc_deque_node *result = parcMemory_Allocate(sizeof(struct parc_deque_node));
+ if (result != NULL) {
+ result->element = element;
+ result->next = next;
+ result->previous = previous;
+ }
+
+ return result;
+}
+
+static void
+_parcDequeNode_Destroy(PARCDeque *deque __attribute__((unused)), struct parc_deque_node **nodePtr)
+{
+ struct parc_deque_node *node = *nodePtr;
+
+ parcMemory_Deallocate((void **) &node);
+ *nodePtr = 0;
+}
+
+static void
+_parcDequeNode_AssertInvariants(struct parc_deque_node *node)
+{
+ assertNotNull(node, "Expected non-null node pointer.");
+ if (node->next != NULL) {
+ assertTrue(node->next->previous == node, "Expected next node to point to this node.");
+ }
+ if (node->previous != NULL) {
+ assertTrue(node->previous->next == node, "Expected previous node to point to this node.");
+ }
+}
+
+static void
+_parcDeque_AssertInvariants(const PARCDeque *deque)
+{
+ assertNotNull(deque, "Parameter cannot be null.");
+ if (deque->head != NULL) {
+ assertTrue(deque->size != 0, "PARCDeque head is not-null, but size is zero.");
+ assertNotNull(deque->tail, "PARCDeque head is not-null, but tail is null.");
+ _parcDequeNode_AssertInvariants(deque->head);
+ _parcDequeNode_AssertInvariants(deque->tail);
+ } else {
+ assertNull(deque->tail, "PARCDeque head is null, but tail is not null.");
+ assertTrue(deque->size == 0, "PARCDeque head is null, but size is not zero.");
+ }
+}
+
+static void
+_parcDeque_Destroy(PARCDeque **dequePtr)
+{
+ PARCDeque *deque = *dequePtr;
+
+ struct parc_deque_node *next = NULL; //deque->head;
+
+ for (struct parc_deque_node *node = deque->head; node != NULL; node = next) {
+ next = node->next;
+ _parcDequeNode_Destroy(deque, &node);
+ }
+}
+
+static struct parc_deque_node *
+_parcDequeNode_Init(PARCDeque *deque __attribute__((unused)))
+{
+ return NULL;
+}
+
+static bool
+_parcDequeNode_Fini(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node __attribute__((unused)))
+{
+ return true;
+}
+
+static struct parc_deque_node *
+_parcDequeNode_Next(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node)
+{
+ if (node == NULL) {
+ return deque->head;
+ }
+ trapOutOfBoundsIf(node->next == NULL, "No more elements.");
+ return node->next;
+}
+
+static bool
+_parcDequeNode_HasNext(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node)
+{
+ if (node == NULL) {
+ return (deque->head != NULL);
+ }
+ return (node->next != NULL);
+}
+
+static void *
+_parcDequeNode_Element(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node)
+{
+ return node->element;
+}
+
+parcObject_ExtendPARCObject(PARCDeque, _parcDeque_Destroy, parcDeque_Copy, NULL, parcDeque_Equals, NULL, NULL, NULL);
+
+static PARCDeque *
+_create(const PARCObjectDescriptor *interface)
+{
+ PARCDeque *result = parcObject_CreateInstance(PARCDeque);
+
+ if (result != NULL) {
+ result->object = *interface;
+ result->head = NULL;
+ result->tail = NULL;
+ result->size = 0;
+ }
+ return result;
+}
+
+PARCIterator *
+parcDeque_Iterator(PARCDeque *deque)
+{
+ PARCIterator *iterator = parcIterator_Create(deque,
+ (void *(*)(PARCObject *))_parcDequeNode_Init,
+ (bool (*)(PARCObject *, void *))_parcDequeNode_HasNext,
+ (void *(*)(PARCObject *, void *))_parcDequeNode_Next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_parcDequeNode_Element,
+ (void (*)(PARCObject *, void *))_parcDequeNode_Fini,
+ NULL);
+
+ return iterator;
+}
+
+PARCDeque *
+parcDeque_Create(void)
+{
+ static PARCObjectDescriptor defaultObjectInterface = {
+ .destroy = (PARCObjectDestroy *) NULL,
+ .copy = (PARCObjectCopy *) _defaultElementCopy,
+ .toString = (PARCObjectToString *) NULL,
+ .equals = (PARCObjectEquals *) _defaultElementEquals,
+ .compare = (PARCObjectCompare *) NULL
+ };
+ return _create(&defaultObjectInterface);
+}
+
+PARCDeque *
+parcDeque_CreateObjectInterface(const PARCObjectDescriptor *interface)
+{
+ return _create(interface);
+}
+
+PARCDeque *
+parcDeque_CreateCustom(bool (*elementEquals)(const void *, const void *), void *(*elementCopy)(const void *))
+{
+ PARCObjectDescriptor objectInterface;
+ parcObject_MetaInitialize(&objectInterface);
+
+ objectInterface.equals = elementEquals != NULL ? elementEquals : _defaultElementEquals;
+ objectInterface.copy = elementCopy != NULL ? elementCopy : _defaultElementCopy;
+
+ return _create(&objectInterface);
+}
+
+parcObject_ImplementAcquire(parcDeque, PARCDeque);
+
+parcObject_ImplementRelease(parcDeque, PARCDeque);
+
+PARCDeque *
+parcDeque_Copy(const PARCDeque *deque)
+{
+ PARCDeque *result = _create(&deque->object);
+
+ struct parc_deque_node *node = deque->head;
+
+ while (node != NULL) {
+ parcDeque_Append(result, deque->object.copy(node->element));
+ node = node->next;
+ }
+
+ return result;
+}
+
+PARCDeque *
+parcDeque_Append(PARCDeque *deque, void *element)
+{
+ struct parc_deque_node *node = _parcDequeNode_Create(element, deque->tail, NULL);
+
+ if (deque->tail == NULL) {
+ deque->tail = node;
+ } else {
+ deque->tail->next = node;
+ deque->tail = node;
+ }
+
+ if (deque->head == NULL) {
+ deque->head = deque->tail;
+ }
+
+ deque->size++;
+
+ return deque;
+}
+
+PARCDeque *
+parcDeque_Prepend(PARCDeque *deque, void *element)
+{
+ struct parc_deque_node *node = _parcDequeNode_Create(element, NULL, deque->head);
+
+ if (deque->head == NULL) {
+ deque->head = node;
+ } else {
+ deque->head->previous = node;
+ deque->head = node;
+ }
+
+ if (deque->tail == NULL) {
+ deque->tail = deque->head;
+ }
+ deque->size++;
+
+ _parcDequeNode_AssertInvariants(node);
+ _parcDeque_AssertInvariants(deque);
+
+ return deque;
+}
+
+void *
+parcDeque_RemoveFirst(PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->head != NULL) {
+ struct parc_deque_node *node = deque->head;
+ result = node->element;
+ if (deque->head == deque->tail) {
+ deque->head = NULL;
+ deque->tail = NULL;
+ } else {
+ deque->head = node->next;
+ deque->head->previous = NULL;
+ }
+ parcMemory_Deallocate((void **) &node);
+ deque->size--;
+ }
+
+ _parcDeque_AssertInvariants(deque);
+
+ return result;
+}
+
+void *
+parcDeque_RemoveLast(PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->tail != NULL) {
+ struct parc_deque_node *node = deque->tail;
+ deque->tail = node->previous;
+ deque->tail->next = NULL;
+
+ result = node->element;
+ parcMemory_Deallocate((void **) &node);
+ deque->size--;
+ }
+
+ _parcDeque_AssertInvariants(deque);
+ return result;
+}
+
+void *
+parcDeque_PeekFirst(const PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->head != NULL) {
+ struct parc_deque_node *node = deque->head;
+ result = node->element;
+ }
+ return result;
+}
+
+void *
+parcDeque_PeekLast(const PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->tail != NULL) {
+ struct parc_deque_node *node = deque->tail;
+ result = node->element;
+ }
+ return result;
+}
+
+size_t
+parcDeque_Size(const PARCDeque *deque)
+{
+ return deque->size;
+}
+
+bool
+parcDeque_IsEmpty(const PARCDeque *deque)
+{
+ return (parcDeque_Size(deque) == 0);
+}
+
+void *
+parcDeque_GetAtIndex(const PARCDeque *deque, size_t index)
+{
+ if (index > (parcDeque_Size(deque) - 1)) {
+ trapOutOfBounds(index, "[0, %zd]", parcDeque_Size(deque) - 1);
+ }
+ struct parc_deque_node *node = deque->head;
+ while (index--) {
+ node = node->next;
+ }
+
+ return node->element;
+}
+
+bool
+parcDeque_Equals(const PARCDeque *x, const PARCDeque *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->object.equals == y->object.equals) {
+ if (x->size == y->size) {
+ struct parc_deque_node *xNode = x->head;
+ struct parc_deque_node *yNode = y->head;
+
+ while (xNode != NULL) {
+ if (x->object.equals(xNode->element, yNode->element) == false) {
+ return false;
+ }
+ xNode = xNode->next;
+ yNode = yNode->next;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+parcDeque_Display(const PARCDeque *deque, const int indentation)
+{
+ if (deque == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCDeque@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCDeque@%p {", (void *) deque);
+
+ struct parc_deque_node *node = deque->head;
+
+ while (node != NULL) {
+ parcDisplayIndented_PrintLine(indentation + 1,
+ ".previous=%11p, %11p=%11p, .next=%11p",
+ node->previous, node, node->element, node->next);
+ node = node->next;
+ }
+
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+ }
+}
diff --git a/libparc/parc/algol/parc_Deque.h b/libparc/parc/algol/parc_Deque.h
new file mode 100755
index 00000000..3e11e845
--- /dev/null
+++ b/libparc/parc/algol/parc_Deque.h
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Deque.h
+ * @ingroup datastructures
+ * @brief PARC Double-ended Queue (Deque)
+ *
+ *
+ */
+#ifndef libparc_parc_Deque_h
+#define libparc_parc_Deque_h
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_deque;
+/**
+ * A double-ended queue.
+ *
+ * @see {@link parcDeque_Create}
+ * @see {@link parcDeque_CreateCustom}
+ */
+typedef struct parc_deque PARCDeque;
+
+/**
+ * Create a `PARCDeque` instance with the default element equality and copy functions.
+ *
+ * The queue is created with no elements.
+ *
+ * The default element equals function is used by the `{@link parcDeque_Equals} function and
+ * simply compares the values using the `==` operator.
+ * Users that need more sophisticated comparisons of the elements need to supply their own
+ * function via the {@link parcDeque_CreateCustom} function.
+ *
+ * @return non-NULL A pointer to a `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCDeque *parcDeque_Create(void);
+
+PARCIterator *parcDeque_Iterator(PARCDeque *deque);
+
+/**
+ * Create a PARCDeque instance that uses the {@link PARCObjectDescriptor} providing functions for element equality and copy function.
+ *
+ * The queue is created with no elements.
+ *
+ * @param [in] interface A pointer to a `PARCObjectDescriptor` instance.
+ *
+ * @return non-NULL A pointer to a `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_CreateObjectInterface(const PARCObjectDescriptor *interface);
+
+/**
+ * Create a `PARCDeque` instance with a custom element equality and copy function.
+ *
+ * The queue is created with no elements.
+ *
+ * The supplied element equals function is used by the `parcDeque_Equals`
+ * function which must return `true` if the elements are equal, and `false` if unequal.
+ *
+ * @param [in] elementEquals The function to be used for equals
+ * @param [in] elementCopy The function to be used for copy
+ *
+ * @return non-NULL A pointer to a `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see {@link parcDeque_CreateObjectInterface}
+ */
+PARCDeque *parcDeque_CreateCustom(bool (*elementEquals)(const void *, const void *), void *(*elementCopy)(const void *));
+
+/**
+ * Acquire a new reference to an instance of `PARCDeque`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] deque The instance of `PARCDeque` to which to refer.
+ *
+ * @return The same value as the input parameter @p deque
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_Acquire(const PARCDeque *deque);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] dequePtr A pointer to a pointer to the instance of `PARCDeque` to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDeque *buffer = parcDeque_Create(10);
+ *
+ * parcDeque_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcDeque_Release(PARCDeque **dequePtr);
+
+/**
+ * Copy a a `PARCDeque` to another.
+ *
+ * @param [in] deque A pointer to an instance of `PARCDeque`
+ *
+ * @return A pointer to a copy of the original instance of `PARCDeque`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCDeque *parcDeque_Copy(const PARCDeque *deque);
+
+/**
+ * Append an element to the tail end of the specified `PARCDeque`
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` to which the element will be appended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCDeque`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCDeque`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_Append(PARCDeque *deque, void *element);
+
+/**
+ * Prepend an element to the head end of the specified `PARCDeque`
+ *
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` to which the element will be prepended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCDeque`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCDeque`
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_Prepend(PARCDeque *deque, void *element);
+
+/**
+ * Return the first element of the specified `PARCDeque` and remove it from the queue
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` from which the first element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_RemoveFirst(PARCDeque *deque);
+
+/**
+ * Return the last element of the specified `PARCDeque` and remove it from the queue
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` from which the last element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_RemoveLast(PARCDeque *deque);
+
+/**
+ * Return the first element of the specified `PARCDeque` but do NOT remove it from the queue
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque` from which the first element will be returned
+ *
+ * @return non NULL A pointer to the first element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_PeekFirst(const PARCDeque *deque);
+
+/**
+ * Return the last element of the specified `PARCDeque` but do NOT remove it from the queue
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque` from which the last element will be returned
+ *
+ * @return non NULL A pointer to the last element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_PeekLast(const PARCDeque *deque);
+
+/**
+ * Return the size of the specified queue
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque`
+ *
+ * @return `size_t` The size of the queue
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+size_t parcDeque_Size(const PARCDeque *deque);
+
+/**
+ * Return True if the `PARCDeque` is empty or False if not.
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque`
+ *
+ * @return bool True if the `PARCDeque` is empty or False if not.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+bool parcDeque_IsEmpty(const PARCDeque *deque);
+
+/**
+ * Get a pointer to the specified element.
+ *
+ * @param [in] deque A pointer to a `PARCDeque` instance.
+ * @param [in] index The index of the element to be retrieved.
+ *
+ * @throws `trapOutOfBounds`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_GetAtIndex(const PARCDeque *deque, size_t index);
+
+/**
+ * Determine if two `PARCDeque` instances are equal.
+ *
+ * This function implements the following equivalence relations on non-null `PARCDeque` instances:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcDeque_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcDeque_Equals(x, y)` must return true if and only if
+ * `parcDeque_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcDeque_Equals(x, y)` returns true and
+ * `parcDeque_Equals(y, z)` returns true,
+ * then `parcDeque_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcDeque_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcDeque_Equals(x, NULL)` must return false.
+ *
+ * Two `PARCDeque` instances with different element equality functions are always unequal.
+ *
+ * @param [in] x A pointer to a `PARCDeque` instance.
+ * @param [in] y A pointer to a `PARCDeque` instance.
+ *
+ * @return true `PARCDeque` x and y are equal.
+ * @return false `PARCDeque` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcDeque_Equals(const PARCDeque *x, const PARCDeque *y);
+
+/**
+ * Print a human readable representation of the given `PARCDeque`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] deque A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDeque *instance = parcDeque_Create();
+ *
+ * parcDeque_Display(instance, 0);
+ *
+ * parcDeque_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcDeque_Display(const PARCDeque *deque, int indentation);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcDeque_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCDeque instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcDeque_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcDeque, PARCDeque);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcDeque_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcDeque_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcDeque, PARCDeque);
+
+/**
+ * Obtain the lock on the given `PARCDeque` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCDeque` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcDeque_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcDeque, PARCDeque);
+
+/**
+ * Try to obtain the advisory lock on the given PARCDeque instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCDeque instance.
+ *
+ * @return true The PARCDeque is locked.
+ * @return false The PARCDeque is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcDeque_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcDeque, PARCDeque);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCDeque` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * @return true The `PARCDeque` was locked and now is unlocked.
+ * @return false The `PARCDeque` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcDeque_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcDeque, PARCDeque);
+
+/**
+ * Determine if the advisory lock on the given `PARCDeque` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * @return true The `PARCDeque` is locked.
+ * @return false The `PARCDeque` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcDeque_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcDeque, PARCDeque);
+
+#endif // libparc_parc_Deque_h
diff --git a/libparc/parc/algol/parc_Dictionary.c b/libparc/parc/algol/parc_Dictionary.c
new file mode 100755
index 00000000..628b08e2
--- /dev/null
+++ b/libparc/parc/algol/parc_Dictionary.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <string.h>
+
+#include <parc/algol/parc_Dictionary.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+struct parc_dictionary {
+ PARCDictionary_CompareKey keyCompareFunction;
+ PARCDictionary_KeyHashFunc keyHashFunction;
+ PARCDictionary_FreeKey keyFreeFunction;
+ PARCDictionary_FreeValue valueFreeFunction;
+ PARCDictionary_ValueEquals valueEqualsFunction;
+ PARCTreeRedBlack *tree;
+};
+
+
+PARCDictionary *
+parcDictionary_Create(PARCDictionary_CompareKey keyCompareFunction,
+ PARCDictionary_KeyHashFunc keyHashFunction,
+ PARCDictionary_FreeKey keyFreeFunction,
+ PARCDictionary_ValueEquals valueEqualsFunction,
+ PARCDictionary_FreeValue valueFreeFunction)
+{
+ assertNotNull(keyCompareFunction, "KeyCompareFunction can't be null");
+ assertNotNull(keyHashFunction, "KeyHashFunction can't be null");
+ PARCDictionary *dictionary = parcMemory_Allocate(sizeof(PARCDictionary));
+ assertNotNull(dictionary, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCDictionary));
+ dictionary->keyCompareFunction = keyCompareFunction;
+ dictionary->keyHashFunction = keyHashFunction;
+ dictionary->keyFreeFunction = keyFreeFunction;
+ dictionary->valueFreeFunction = valueFreeFunction;
+ dictionary->valueEqualsFunction = valueEqualsFunction;
+ dictionary->tree = parcTreeRedBlack_Create(keyCompareFunction,
+ keyFreeFunction,
+ NULL,
+ valueEqualsFunction,
+ valueFreeFunction,
+ NULL);
+ return dictionary;
+}
+
+
+void
+parcDictionary_Destroy(PARCDictionary **dictionaryPointer)
+{
+ assertNotNull(dictionaryPointer, "Pointer to dictionary pointer can't be NULL");
+ assertNotNull(*dictionaryPointer, "Pointer to dictionary can't be NULL");
+ parcTreeRedBlack_Destroy(&((*dictionaryPointer)->tree));
+ parcMemory_Deallocate((void **) dictionaryPointer);
+ *dictionaryPointer = NULL;
+}
+
+void
+parcDictionary_SetValue(PARCDictionary *dictionary, void *key, void *value)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ parcTreeRedBlack_Insert(dictionary->tree, key, value);
+}
+
+void *
+parcDictionary_GetValue(PARCDictionary *dictionary, const void *key)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ return parcTreeRedBlack_Get(dictionary->tree, key);
+}
+
+void *
+parcDictionary_RemoveValue(PARCDictionary *dictionary, const void *key)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ return parcTreeRedBlack_Remove(dictionary->tree, key);
+}
+
+void
+parcDictionary_RemoveAndDestroyValue(PARCDictionary *dictionary, const void *key)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ parcTreeRedBlack_RemoveAndDestroy(dictionary->tree, key);
+}
+
+PARCArrayList *
+parcDictionary_Keys(const PARCDictionary *dictionary)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Keys(dictionary->tree);
+}
+
+PARCArrayList *
+parcDictionary_Values(const PARCDictionary *dictionary)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Values(dictionary->tree);
+}
+
+size_t
+parcDictionary_Size(const PARCDictionary *dictionary)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Size(dictionary->tree);
+}
+
+int
+parcDictionary_Equals(const PARCDictionary *dictionary1, const PARCDictionary *dictionary2)
+{
+ assertNotNull(dictionary1, "dictionary pointer can't be NULL");
+ assertNotNull(dictionary2, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Equals(dictionary1->tree, dictionary2->tree);
+}
diff --git a/libparc/parc/algol/parc_Dictionary.h b/libparc/parc/algol/parc_Dictionary.h
new file mode 100755
index 00000000..1ba98a65
--- /dev/null
+++ b/libparc/parc/algol/parc_Dictionary.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Dictionary.h
+ * @ingroup datastructures
+ * @brief
+ *
+ * The `PARCDictionary` is a dictionary of key value tuples.
+ *
+ */
+#ifndef libparc_parc_Dictionary_h
+#define libparc_parc_Dictionary_h
+
+#include <parc/algol/parc_ArrayList.h>
+
+#include <stdint.h>
+
+struct parc_dictionary;
+
+
+/**
+ * @typedef PARCDictionary
+ * @brief A PARCDictionary is a dictionary of key-values
+ */
+typedef struct parc_dictionary PARCDictionary;
+
+/**
+ * @typedef `PARCDictionary_CompareKey`
+ *
+ * @brief Compare two dictionary keys
+ *
+ * @param [in] key1 First dictionary key
+ * @param [in] key2 Second dictionary key
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef int (*PARCDictionary_CompareKey)(const void *key1,
+ const void *key2);
+/**
+ * @typedef `PARCDictionary_ValueEquals`
+ *
+ * @brief Compare two values
+ *
+ * @param [in] value1 A pointer to the First value
+ * @param [in] value2 A pointer to the Second value
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef bool (*PARCDictionary_ValueEquals)(const void *value1, const void *value2);
+
+
+/**
+ * @typedef `PARCDictionary_KeyHashFunc`
+ * @brief The key hash function must return a 32 bit hash of the key
+ * @param [in] key pointer to the key to be hashed
+ * @return uint32 hash
+ */
+
+typedef uint32_t (*PARCDictionary_KeyHashFunc)(const void *key);
+
+/**
+ * @typedef `PARCDictionary_FreeValue`
+ * @brief The free value must free a value.
+ * This will be called when a value for a key is changed.
+ * It will also be used when the Dictionary is destroyed on any
+ * values in the dictionary.
+ * @param [in,out] value The pointer to the pointer of the value to be freed.
+ */
+
+typedef void (*PARCDictionary_FreeValue)(void **value);
+
+/**
+ * @typedef `PARCDictionary_FreeKey`
+ * @brief The free key must free a key.
+ * This function will be called when the value for a key is removed from the
+ * dictionary. It's also called when the dictionary is destroyed.
+ * @param [in,out] key The pointer to the pointer to the key to be freed.
+ */
+
+typedef void (*PARCDictionary_FreeKey)(void **key);
+
+/**
+ * Create a Dictionary.
+ * You MUST set the function to compare keys and hash keys.
+ * You can give NULL as the free function of the key and the data,
+ * but why would you do that? :-)
+ *
+ * @param [in] keyCompareFunction The function that compares 2 keys (can't be NULL)
+ * @param [in] keyHashFunction The function to hash the keys to 32 bit values (can't be NULL)
+ * @param [in] keyFreeFunction The function to free the key (can be NULL)
+ * @param [in] valueEqualsFunction The function to know that values are equal. If NULL then values won't be compared on equality.
+ * @param [in] valueFreeFunction The function to free the values (can be NULL)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDictionary *parcDictionary_Create(PARCDictionary_CompareKey keyCompareFunction,
+ PARCDictionary_KeyHashFunc keyHashFunction,
+ PARCDictionary_FreeKey keyFreeFunction,
+ PARCDictionary_ValueEquals valueEqualsFunction,
+ PARCDictionary_FreeValue valueFreeFunction);
+
+/**
+ * Destroy a Dictionary. If the Free functions were passed to the constructor and are not NULL
+ * they will be called for every element.
+ *
+ * @param [in,out] dictionaryPointer A pointer to the pointer to the instance of `PARCDictionary` to be destroyed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcDictionary_Destroy(PARCDictionary **dictionaryPointer);
+
+/**
+ * Set a value for a key.
+ * Both key and value will be referenced by the Dictionary. No memory copies will happen.
+ *
+ * If the key does not exist a new dictionary entry will be added pointing to the value.
+ *
+ * If the key does exists then the old value will be freed using the valueFree function (if not NULL).
+ * The old key will also be freed using the keyFree function (if not NULL).
+ *
+ * @param [in,out] dictionary A pointer to the specified `PARCDictionary`
+ * @param [in] key The key to insert in the dictionary. Can't be NULL.
+ * @param [in] value The value to associate with that key. Can't be NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+void parcDictionary_SetValue(PARCDictionary *dictionary, void *key, void *value);
+
+/**
+ * Get a value from the dictionary associated with a specific key.
+ *
+ * @param [in] dictionary A PARCDictionary
+ * @param [in] key A pointer to the key. It must be valid as a parameter to the key compare function of the
+ * dictionary
+ * @return A pointer to the value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcDictionary_GetValue(PARCDictionary *dictionary, const void *key);
+
+/**
+ * Remove a value from the dictionary. This will return the value referenced by the key. It will remove it
+ * in the process. The key will be freed with the keyFree function (if not NULL)
+ *
+ * @param [in,out] dictionary A `PARCDictionary`
+ * @param [in] key A pointer to the key. It must be valid as a parameter to the key compare function of the dictionary.
+ * @return A pointer to the value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcDictionary_RemoveValue(PARCDictionary *dictionary, const void *key);
+
+/**
+ * Delete an entry from the dictionary.
+ * This will remove an entry from the dictionary and free both the key and the value using the functions
+ * provided at the creation of the dictionary.
+ *
+ * @param [in,out] dictionary A pointer to an instance of `PARCDictionary`
+ * @param [in] key A pointer to the key. It must be valid as a parameter to the key compare function of the dictionary.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcDictionary_RemoveAndDestroyValue(PARCDictionary *dictionary, const void *key);
+
+/**
+ * Get a list of the keys from this dictionary.
+ *
+ * @param [in] dictionary A `PARCDictionary`
+ * @return A pointer to a {@link PARCArrayList} of (pointers to) keys. All of these keys will be valid keys in the dictionary.
+ * The caller will own the list of keys and should destroy it when done. The caller will not own
+ * the key themselves. (Destroying the `PARCArrayList` should be enough).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcDictionary_Keys(const PARCDictionary *dictionary);
+
+/**
+ * Get a list of the values from this dictionary.
+ * The caller will own the list of values and should destroy it when done. The caller will not own
+ * the values themselves. Destroying the {@link PARCArrayList} should be enough.
+ *
+ * Note that if the Dictionary is destroyed the value pointers might no longer point to valid values.
+ *
+ * @param [in] dictionary A pointer to an instance of `PARCDictionary`
+ * @return A pointer to a `PARCArrayList` of (pointers to) values.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcDictionary_Values(const PARCDictionary *dictionary);
+
+/**
+ * Return the number of entries in the dictionary.
+ *
+ * @param [in] dictionary A pointer to an instance of `PARCDictionary`
+ * @return The number of keys in the dictionary.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcDictionary_Size(const PARCDictionary *dictionary);
+
+
+/**
+ * Determine if two `PARCDictionary` instances are equal.
+ *
+ * Two `PARCDictionary` instances are equal if, and only if, the trees are equal
+ *
+ * The following equivalence relations on non-null `PARCDictionary` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCDictionary_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcDictionary_Equals(x, y)` must return true if and only if
+ * `parcDictionary_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcDictionary_Equals(x, y)` returns true and
+ * `parcDictionary_Equals(y, z)` returns true,
+ * then `parcDictionary_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcDictionary_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcDictionary_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] dictionary1 A pointer to a `PARCDictionary` instance.
+ * @param [in] dictionary2 A pointer to a `PARCDictionary` instance.
+ * @return true if the two `PARCDictionary` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDictionary *a = parcDictionary_Create();
+ * PARCDictionary *b = parcDictionary_Create();
+ *
+ * if (parcDictionary_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+int parcDictionary_Equals(const PARCDictionary *dictionary1, const PARCDictionary *dictionary2);
+#endif // libparc_parc_Dictionary_h
diff --git a/libparc/parc/algol/parc_DisplayIndented.c b/libparc/parc/algol/parc_DisplayIndented.c
new file mode 100755
index 00000000..5e043c15
--- /dev/null
+++ b/libparc/parc/algol/parc_DisplayIndented.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+
+static char *_spaces = " ";
+
+static size_t _indentationFactor = 2;
+
+static size_t
+_indent(int indentation)
+{
+ size_t result = 0;
+
+ if (indentation > 0) {
+ result = write(1, _spaces, indentation * _indentationFactor);
+ assertTrue(result == (indentation * _indentationFactor),
+ "Write(2) failed to write %zd bytes.", indentation * _indentationFactor);
+ }
+ return result;
+}
+
+static void
+_parcDisplayIndented_Print(int indentation, char *string)
+{
+ char *start = string;
+ char *end = strchr(start, '\n');
+
+ while (start != NULL) {
+ _indent(indentation);
+ if (end != NULL) {
+ ssize_t nwritten = write(1, start, end - start + 1);
+ assertTrue(nwritten >= 0, "Error calling write");
+ start = end + 1;
+ } else {
+ ssize_t nwritten = write(1, start, strlen(start));
+ assertTrue(nwritten >= 0, "Error calling write");
+ break;
+ }
+ end = strchr(start, '\n');
+ }
+}
+
+void
+parcDisplayIndented_PrintLine(int indentation, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ char *cString;
+ int length = vasprintf(&cString, format, ap);
+ assertTrue(length >= 0, "Error in vasprintf");
+
+ va_end(ap);
+
+ _parcDisplayIndented_Print(indentation, cString);
+
+ ssize_t nwritten = write(1, "\n", 1);
+ assertTrue(nwritten >= 0, "Error calling write");
+
+ free(cString);
+}
+
+void
+parcDisplayIndented_PrintMemory(int indentation, size_t length, const char memory[length])
+{
+ int bytesPerLine = 16;
+
+ char accumulator[bytesPerLine + 1];
+ memset(accumulator, ' ', bytesPerLine);
+ accumulator[bytesPerLine] = 0;
+
+ char *cString;
+ for (size_t offset = 0; offset < length; /**/) {
+ int nwritten = asprintf(&cString, "%p=[", &memory[offset]);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+ _parcDisplayIndented_Print(indentation, cString);
+ free(cString);
+
+ size_t bytesInLine = (length - offset) < bytesPerLine ? (length - offset) : bytesPerLine;
+ for (size_t i = 0; i < bytesInLine; i++) {
+ char c = memory[offset + i];
+ printf("0x%02x, ", c & 0xFF);
+ accumulator[i] = isprint(c) ? c : '.';
+ }
+ offset += bytesInLine;
+ }
+ printf(" %s]\n", accumulator);
+}
diff --git a/libparc/parc/algol/parc_DisplayIndented.h b/libparc/parc/algol/parc_DisplayIndented.h
new file mode 100644
index 00000000..753f942d
--- /dev/null
+++ b/libparc/parc/algol/parc_DisplayIndented.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_DisplayIndented.h
+ * @ingroup developer
+ * @brief Support for displaying information on the console.
+ *
+ *
+ */
+#ifndef libparc_parc_DisplayIndented_h
+#define libparc_parc_DisplayIndented_h
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+/**
+ * Print an indented, formatted string on standard output.
+ *
+ * The line is automatically terminated with a new line.
+ *
+ * @param [in] indentation The indentation level of the output.
+ * @param [in] format The format string.
+ * @param [in] ... A variable number of arguments.
+ *
+ * Example:
+ * @code
+ * {
+ * parcDisplayIndented_PrintLine(2, "This is printed on standard output, at indentation level 2");
+ * }
+ * @endcode
+ */
+void parcDisplayIndented_PrintLine(int indentation, const char *format, ...);
+
+/**
+ * Print memory.
+ *
+ * @param [in] indentation The indentation level of the output.
+ * @param [in] length The length of the array.
+ * @param [in] memory The memory array.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcDisplayIndented_PrintMemory(int indentation, size_t length, const char *memory);
+#endif // libparc_parc_DisplayIndented_h
diff --git a/libparc/parc/algol/parc_ElasticString.h b/libparc/parc/algol/parc_ElasticString.h
new file mode 100755
index 00000000..c6e39eb1
--- /dev/null
+++ b/libparc/parc/algol/parc_ElasticString.h
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_ElasticString.h
+ * @ingroup memory
+ * @brief An elastic C string.
+ *
+ * An elastic string is a dynamic array of characters which are readily expressed as a
+ * nul-terminated C string.
+ *
+ */
+#ifndef libparc_parc_ElasticString_h
+#define libparc_parc_ElasticString_h
+
+#include <stdarg.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_elastic_string;
+typedef struct parc_elastic_string PARCElasticString;
+
+/**
+ * Perform validation on a pointer to a `PARCElasticString`.
+ *
+ * If invalid, this function will abort the running process.
+ *
+ * @param * string A pointer to a `PARCElasticString` to validate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_AssertValid(string);
+ * }
+ * @endcode
+ */
+void parcElasticString_AssertValid(const PARCElasticString *string);
+
+/**
+ * Create an empty `PARCElasticString` instance.
+ *
+ * The instance will be empty upon initialization (i.e., `parcElasticString_ToString()` will
+ * return an empty string), but characters and strings may be inserted/appended to
+ * the instance to produce usable content,
+ *
+ * @return A pointer to an allocated `PARCElasticString` that must be freed with `parcElasticString_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * // use the string as necessary
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_Create(void);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param * string A pointer to a pointer to the instance to release.
+ *
+ * @return The number of remaining references to the object.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCElasticString *buffer = parcElasticString_Create();
+ *
+ * parcElasticString_Release(&pathName);
+ * }
+ * @endcode
+ */
+void parcElasticString_Release(PARCElasticString **string);
+
+/**
+ * Retrieve the number of remaining bytes between the current position
+ * in the string and its (flexible) limit.
+ *
+ * @param * string A pointer to an `PARCElasticString` instance.
+ *
+ * @return The non-negative number of characters remaining between the position and limit.
+ *
+ * Example:
+ * @code
+ * {
+ * char *inputString = "Hello World";
+ * size_t inputLength = strlen(input);
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, inputString);
+ * parcElasticString_Flip(string);
+ * size_t numRemaining = parcElasticString_Remaining(string);
+ *
+ * // numRemaining == inputLength
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+size_t parcElasticString_Remaining(const PARCElasticString *string);
+
+/**
+ * Set the limit to the current position, then the position to zero.
+ * If the mark is defined, it is invalidated,
+ * and any subsequent operation that requires the mark will abort until the mark
+ * is set again via `parcElasticString_Mark`.
+ *
+ * @param * string A pointer to an `PARCElasticString` instance.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * char *inputString = "Hello World";
+ * size_t inputLength = strlen(input);
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, inputString);
+ * parcElasticString_Flip(string);
+ * size_t numRemaining = parcElasticString_Remaining(string);
+ *
+ * // numRemaining == inputLength
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_Flip(PARCElasticString *string);
+
+/**
+ * Return the given `PARCElasticString`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ *
+ * @return The given `PARCElasticString`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t currentPosition = parcBuffer_Position(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_SetPosition
+ */
+size_t parcElasticString_Position(const PARCElasticString *string);
+
+/**
+ * Set the position in the given `PARCElasticString`.
+ *
+ * If the mark is defined and larger than the new position then it is invalidated.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * newPosition The new position for the `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, "Hello World");
+ *
+ * parcElasticString_SetPosition(string, 0);
+ *
+ * // position is now at 0, instead of at the end of "Hello World"
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_Position
+ */
+PARCElasticString *parcElasticString_SetPosition(PARCElasticString *string, size_t newPosition);
+
+/**
+ * Append an array with the specified number of bytes to the end of this `PARCElasticString` instance.
+ *
+ * The position of the string is advanced by the length of the array.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * array A pointer to the array containing the bytes to append.
+ * @param * length The length of the input array.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * uint8_t * appendArray = { 0x00, 0x01, 0x02, 0x03, 0x04 };
+ * parcElasticString_PutArray(string, appendArray, 5);
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutArray(PARCElasticString *string, const char *array, size_t length);
+
+/**
+ * Append a C-string to the end of this `PARCElasticString` instance.
+ *
+ * The position of the string is advanced by the length of the string.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * cString A pointer to a nul-terminated C string to append to this `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_PutString(string, "Hello World");
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutArray
+ */
+PARCElasticString *parcElasticString_PutString(PARCElasticString *string, const char *cString);
+
+/**
+ * Append the contents of a `PARCBuffer` instance to the end of the `PARCElasticString` instance.
+ *
+ * The position of the string is advanced by the length of the buffer.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * uint8_t * array = { 'H', 'e', 'l', 'l', 'o' };
+ * PARCBuffer *endBuffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutArray(endBuffer, 5, array);
+ * parcElasticString_PutBuffer(string, endBuffer);
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutBuffer(PARCElasticString *string, PARCBuffer *buffer);
+
+/**
+ * Append a single character (byte) to the end of this string.
+ *
+ * The position of the string is advanced by one (1).
+ *
+ * @param * string A pointer to `PARCElasticString`
+ * @param * character A `char` value to append.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_PutChar(string, 'H');
+ * parcElasticString_PutChar(string, 'e');
+ * parcElasticString_PutChar(string, 'l');
+ * parcElasticString_PutChar(string, 'l');
+ * parcElasticString_PutChar(string, 'o');
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutChar(PARCElasticString *string, const char character);
+
+/**
+ * Put a variable number of characters into the `PARCElasticString`.
+ *
+ * @param * string The `PARCElasticString` to receive the characters.
+ * @param * count The number of characters to insert into the `PARCElasticString`
+ * @param * ... The characters to insert into the `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_PutChar(string, 5, 'H', 'e', 'l', 'l', 'o');
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutChars(PARCElasticString *string, unsigned int count, ...);
+
+/**
+ * Append an arbitrary number of C-style strings to the given `PARCElasticString` instance.
+ *
+ * @param * string A pointer to `PARCElasticString`
+ * @param * ... The nul-terminated, C-style strings to append to the given `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *baseString = parcElasticString_Create();
+ * parcElasticString_PutString(baseString, "Hello");
+ * uint8_t * string1 = {' ', '\0'};
+ * uint8_t * string2 = {'W', 'o', 'r', 'l', 'd', '\0'};
+ *
+ * parcElasticString_PutStrings(baseString, string1, string2);
+ *
+ * printf("String = %s\n", parcElasticString_ToString(baseString));
+ *
+ * parcElasticString_Release(&baseString);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_PutStrings(PARCElasticString *string, ...);
+
+/**
+ * Append a formatted nul-terminated, C-style string string to the given `PARCElasticString` instance.
+ *
+ * @param * string A pointer to `PARCElasticString`.
+ * @param * format The format string
+ * @param * ... Remaining parameters used to format the string.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_Format(string, "Hello %s\n", "World");
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_Format(PARCElasticString *string, const char *format, ...) \
+ __attribute__((format(printf, 2, 3)));
+
+/**
+ * Retrieve a handle to the `PARCBuffer` instance. The reference count is not increased.
+ *
+ * @param * string A pointer to `PARCElasticString`.
+ *
+ * @return The `PARCBuffer` instance used to encapsulate the `PARCElasticString` contents.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, "Hello World");
+ *
+ * PARCBuffer *buffer = parcElasticString_ToBuffer(string);
+ * printf("String in hex = %s\n", parcBuffer_ToHexString(buffer));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcElasticString_ToBuffer(const PARCElasticString *string);
+
+/**
+ * Produce a C string representation of the given `PARCElasticString`.
+ *
+ * Produce an allocated, nul-terminated string representation of the given `PARCElasticString`.
+ * The result must be freed by the caller via the `parcMemory_Deallocate()` function.
+ *
+ * @param * string A pointer to `PARCElasticString`.
+ *
+ * @return A pointer to an allocated array containing a nul-terminated string the must be freed via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, "Hello World");
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+char *parcElasticString_ToString(const PARCElasticString *string);
+#endif // libparc_parc_ElasticString_h
diff --git a/libparc/parc/algol/parc_Environment.c b/libparc/parc/algol/parc_Environment.c
new file mode 100644
index 00000000..2955a139
--- /dev/null
+++ b/libparc/parc/algol/parc_Environment.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Environment.h>
+#include <parc/algol/parc_File.h>
+
+const char *
+parcEnvironment_GetHomeDirectory(void)
+{
+ char *result = getenv("HOME");
+ return result;
+}
+
+PARCFile *
+parcEnvironment_HomeDirectory(void)
+{
+ char *path;
+
+ if ((path = getenv("HOME")) == NULL) {
+ path = getpwuid(getuid())->pw_dir;
+ }
+
+ return parcFile_Create(path);
+}
diff --git a/libparc/parc/algol/parc_Environment.h b/libparc/parc/algol/parc_Environment.h
new file mode 100755
index 00000000..04610176
--- /dev/null
+++ b/libparc/parc/algol/parc_Environment.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Environment.h
+ * @ingroup inputoutput
+ * @brief Functions to access and manipulate the runtime environment.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libparc_parc_Environment_h
+#define libparc_parc_Environment_h
+
+/**
+ *
+ * Get the current home directory for the running process.
+ *
+ * @return A C string containing the name of the home directory.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *parcEnvironment_GetHomeDirectory(void);
+#endif // libparc_parc_Environment_h
diff --git a/libparc/parc/algol/parc_Event.c b/libparc/parc/algol/parc_Event.c
new file mode 100755
index 00000000..0a8391aa
--- /dev/null
+++ b/libparc/parc/algol/parc_Event.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_debug_enabled = 0;
+
+#define parcEvent_LogDebug(parcEvent, ...) \
+ if (_parc_event_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEvent->parcEventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+
+/**
+ * @typedef PARCEvent
+ * @brief A structure containing private event state data variables
+ */
+struct PARCEvent {
+ /**
+ * The event instance.
+ */
+ struct event *event;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *parcEventScheduler;
+
+ // Interpose on callback
+ PARCEvent_Callback *callback;
+ void *callbackUserData;
+
+ void *user_data;
+};
+
+static void
+_parc_event_callback(evutil_socket_t fd, short flags, void *context)
+{
+ PARCEvent *parcEvent = (PARCEvent *) context;
+ parcEvent_LogDebug(parcEvent, "_parc_event_callback(fd=%x,flags=%x,parcEvent=%p)\n", fd, flags, parcEvent);
+
+ parcEvent->callback((int) fd, internal_libevent_type_to_PARCEventType(flags), parcEvent->callbackUserData);
+}
+
+PARCEvent *
+parcEvent_Create(PARCEventScheduler *parcEventScheduler, int fd, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs)
+{
+ PARCEvent *parcEvent = parcMemory_Allocate(sizeof(PARCEvent));
+ assertNotNull(parcEvent, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEvent));
+
+ parcEvent->parcEventScheduler = parcEventScheduler;
+ parcEvent->callback = callback;
+ parcEvent->callbackUserData = callbackArgs;
+
+ parcEvent->event = event_new(parcEventScheduler_GetEvBase(parcEventScheduler), fd,
+ internal_PARCEventType_to_libevent_type(flags), _parc_event_callback, parcEvent);
+ assertNotNull(parcEvent->event, "Could not create a new event!");
+
+ parcEvent_LogDebug(parcEvent,
+ "parcEvent_Create(base=%p,fd=%x,events=%x,cb=%p,args=%p)\n",
+ parcEventScheduler_GetEvBase(parcEventScheduler), fd, flags, callback, parcEvent);
+
+ return parcEvent;
+}
+
+int
+parcEvent_Start(PARCEvent *parcEvent)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Start(%p)\n", parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Start must be passed a valid event!");
+
+ int result = event_add(parcEvent->event, NULL);
+ return result;
+}
+
+int
+parcEvent_Stop(PARCEvent *parcEvent)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Stop(%p)\n", parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Stop must be passed a valid event!");
+
+ int result = event_del(parcEvent->event);
+ return result;
+}
+
+int
+parcEvent_Poll(PARCEvent *parcEvent, PARCEventType event)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Stop(%p)\n", parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Stop must be passed a valid event!");
+
+ int result = event_pending(parcEvent->event, event, NULL);
+ return result;
+}
+
+void
+parcEvent_Destroy(PARCEvent **parcEvent)
+{
+ parcEvent_LogDebug((*parcEvent), "parcEvent_Destroy(%p)\n", *parcEvent);
+ assertNotNull(*parcEvent, "parcEvent_Destroy must be passed a valid parcEvent!");
+ assertNotNull((*parcEvent)->event, "parcEvent_Destroy passed a null event!");
+
+ event_free((*parcEvent)->event);
+ parcMemory_Deallocate((void **) parcEvent);
+}
+
+int
+parcEvent_SetPriority(PARCEvent *parcEvent, PARCEventPriority priority)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Stop(%p)\n", parcEvent);
+
+ return event_priority_set(parcEvent->event, internal_PARCEventPriority_to_libevent_priority(priority));
+}
+
+void
+parcEvent_EnableDebug(void)
+{
+ _parc_event_debug_enabled = 1;
+}
+
+void
+parcEvent_DisableDebug(void)
+{
+ _parc_event_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_Event.h b/libparc/parc/algol/parc_Event.h
new file mode 100644
index 00000000..3f2fde98
--- /dev/null
+++ b/libparc/parc/algol/parc_Event.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Event.h
+ * @ingroup events
+ * @brief Event management
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_Event_h
+#define libparc_parc_Event_h
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <parc/algol/parc_EventScheduler.h>
+
+/**
+ * @typedef PARCEventType
+ * @brief An enumeration of event types, with an additional persist flag
+ */
+typedef enum {
+ PARCEventType_None = 0x00,
+ PARCEventType_Timeout = 0x01,
+ PARCEventType_Read = 0x02,
+ PARCEventType_Write = 0x04,
+ PARCEventType_Signal = 0x08,
+ PARCEventType_Persist = 0x10,
+ PARCEventType_EdgeTriggered = 0x20
+} PARCEventType;
+
+/**
+ * @typedef PARCEventPriority
+ * @brief Priority flags for queue scheduling, these currently match the RTA_*_PRIORITY
+ * this will eventually be replaced.
+ */
+typedef enum {
+ PARCEventPriority_Maximum = 0,
+ PARCEventPriority_Normal = 1,
+ PARCEventPriority_Minimum = 2,
+ PARCEventPriority_NumberOfPriorities = 3
+} PARCEventPriority;
+
+/**
+ * @typedef PARCEvent_Callback
+ * @brief Event callback definition
+ */
+typedef void (PARCEvent_Callback)(int fileDescriptor, PARCEventType type, void *user_data);
+
+/**
+ * @typedef PARCEvent
+ * @brief A structure containing private libevent state data variables
+ */
+typedef struct PARCEvent PARCEvent;
+
+/**
+ * Create a new PARCEvent instance.
+ *
+ * A new PARCEvent instance is returned.
+ *
+ * @param [in] parcEventScheduler base instance
+ * @param [in] fileDescriptor file descriptor to monitor
+ * @param [in] events to catch
+ * @param [in] callback function
+ * @param [in] callbackArgs function private arguments
+ * @returns A pointer to the a PARCEvent instance.
+ *
+ * Example:
+ * @code
+ * static void
+ * _read_callback(int fileDescriptor, PARCEventType type, void *args)
+ * {
+ * }
+ *
+ * {
+ * PARCEventScheduler *eventScheduler = parcEventScheduer_Create();
+ * PARCEvent *event = parcEvent_Create(eventScheduler, fileDescriptor, PARCEvent_ReadEvent, _read_callback, _read_callback_args);
+ * }
+ * @endcode
+ *
+ */
+PARCEvent *parcEvent_Create(PARCEventScheduler *parcEventScheduler, int fileDescriptor, PARCEventType events, PARCEvent_Callback *callback, void *callbackArgs);
+
+/**
+ * Start an event instance.
+ *
+ * @param [in] parcEvent instance to start
+ * @returns -1 on error, 0 on success if nothing changed in the parcEvent backend, and 1 on success if something did.
+ *
+ * Example:
+ * @code
+ * startEvent(PARCEvent *parcEvent)
+ * {
+ * return parcEvent_Start(parcEvent);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_Start(PARCEvent *parcEvent);
+
+/**
+ * Stop a parcEvent instance.
+ *
+ * @param [in] parcEvent instance to stop
+ * @returns -1 on error, 0 on success.
+ *
+ * Example:
+ * @code
+ * removeEvent(PARCEvent *parcEvent)
+ * {
+ * return parcEvent_Stop(parcEvent);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_Stop(PARCEvent *parcEvent);
+
+/**
+ * Poll if an event is available to process
+ *
+ * @param [in] parcEvent instance to stop
+ * @param [in] event type to poll for
+ * @returns -1 on error, 0 on success.
+ *
+ * Example:
+ * @code
+ * pollReadEvent(PARCEvent *parcEvent)
+ * {
+ * return parcEvent_Poll(parcEvent, PARCEvent_ReadEvent);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_Poll(PARCEvent *parcEvent, PARCEventType event);
+
+/**
+ * Destroy a parcEvent instance.
+ *
+ * @param [in] parcEvent address of instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_Destroy(&parcEvent);
+ * }
+ * @endcode
+ *
+ */
+void parcEvent_Destroy(PARCEvent **parcEvent);
+
+/**
+ * Set a parcEvent instances priority.
+ *
+ * @param [in] parcEvent instance to modify
+ * @param [in] priority to set to
+ * @returns -1 on error, 0 on success.
+ *
+ * Example:
+ * @code
+ * {
+ * return parcEvent_SetPriority(parcEvent, priority);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_SetPriority(PARCEvent *parcEvent, PARCEventPriority priority);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEvent_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEvent_DisableDebug(void);
+#endif // libparc_parc_Event_h
diff --git a/libparc/parc/algol/parc_EventBuffer.c b/libparc/parc/algol/parc_EventBuffer.c
new file mode 100644
index 00000000..49ba3354
--- /dev/null
+++ b/libparc/parc/algol/parc_EventBuffer.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventBuffer.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static PARCLog *parcEventBufferDebugLog = NULL;
+
+#define parcEventBuffer_LogDebug(parcEvent, ...) \
+ if (parcEventBufferDebugLog) \
+ parcLog_Debug(parcEventBufferDebugLog, __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <event2/buffer.h>
+
+/**
+ * @typedef PARCEventBuffer
+ * @brief A structure containing private libevent state data variables
+ *
+ * The evbuffer either points to an evbuffer owned by the bufferevent, or an
+ * allocated evbuffer (allocated_evbuffer) that is our responsibility to destroy.
+ */
+struct PARCEventBuffer {
+ struct evbuffer *evbuffer;
+ struct evbuffer *allocated_evbuffer;
+};
+
+PARCEventBuffer *
+parcEventBuffer_Create(void)
+{
+ internal_parc_initializeLibevent();
+ struct evbuffer *new_evbuffer = evbuffer_new();
+ assertNotNull(new_evbuffer, "libevent returned a null evbuffer.\n");
+
+ PARCEventBuffer *parcEventBuffer = parcMemory_AllocateAndClear(sizeof(PARCEventBuffer));
+ assertNotNull(parcEventBuffer, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventBuffer));
+ parcEventBuffer->allocated_evbuffer = new_evbuffer;
+ parcEventBuffer->evbuffer = parcEventBuffer->allocated_evbuffer;
+
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_Create() = %p\n", parcEventBuffer);
+
+ return parcEventBuffer;
+}
+
+void
+parcEventBuffer_Destroy(PARCEventBuffer **parcEventBuffer)
+{
+ parcEventBuffer_LogDebug((*parcEventBuffer), "parcEventBuffer_Destroy(parcEventBuffer=%p)\n", *parcEventBuffer);
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Destroy was passed a null parcEventBuffer pointer\n");
+ assertNotNull(*parcEventBuffer, "parcEventBuffer_Destroy was passed a null parcEventBuffer\n");
+
+ // Destroy allocated eveventBuffer if it was allocated by us, otherwise it's owned by bufferevent
+ if ((*parcEventBuffer)->allocated_evbuffer) {
+ parcEventBuffer_LogDebug((*parcEventBuffer), "parcEventBuffer_Destroy(parcEventBuffer=%p) freeing evbuffer %p\n", *parcEventBuffer, (*parcEventBuffer)->allocated_evbuffer);
+ evbuffer_free((*parcEventBuffer)->allocated_evbuffer);
+ }
+ parcMemory_Deallocate((void **) parcEventBuffer);
+ parcEventBuffer_LogDebug((*parcEventBuffer), "parcEventBuffer_Destroy() buffer already deallocated\n");
+}
+
+bool
+parcEventBuffer_IsValid(const PARCEventBuffer *eventBuffer)
+{
+ bool result = false;
+
+ if (eventBuffer != NULL) {
+ if (eventBuffer->evbuffer) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcEventBuffer_AssertValid(const PARCEventBuffer *eventBuffer)
+{
+ assertTrue(parcEventBuffer_IsValid(eventBuffer),
+ "PARCEventBuffer@%p is not valid.", (void *) eventBuffer);
+}
+
+size_t
+parcEventBuffer_GetLength(PARCEventBuffer *parcEventBuffer)
+{
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_GetLength(parcEventBuffer=%p)\n", parcEventBuffer);
+// parcEventBuffer_OptionalAssertValid(parcEventBuffer);
+ assertNotNull(parcEventBuffer, "parcEventBuffer_GetLength was passed a null parcEventBuffer\n");
+
+ if (parcEventBuffer->evbuffer) {
+ return evbuffer_get_length(parcEventBuffer->evbuffer);
+ } else {
+ return 0;
+ }
+}
+
+uint8_t *
+parcEventBuffer_Pullup(PARCEventBuffer *parcEventBuffer, ssize_t size)
+{
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_Pullup(parcEventBuffer=%p,size=%zx)\n", parcEventBuffer, size);
+
+ parcEventBuffer_OptionalAssertValid(parcEventBuffer);
+// assertNotNull(parcEventBuffer, "parcEventBuffer_Pullup was passed a null parcEventBuffer\n");
+// assertNotNull(parcEventBuffer->evbuffer, "parcEventBuffer_Pullup was passed a null libevent evbuffer\n");
+
+ return evbuffer_pullup(parcEventBuffer->evbuffer, (ev_ssize_t) size);
+}
+
+int
+parcEventBuffer_ReadIntoBuffer(PARCEventBuffer *source, PARCEventBuffer *destination, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(source);
+ parcEventBuffer_OptionalAssertValid(destination);
+// assertNotNull(source, "parcEventBuffer_ReadIntoBuffer was passed a null source buffer\n");
+// assertNotNull(source->evbuffer, "parcEventBuffer_ReadIntoBuffer was passed a null source evbuffer\n");
+// assertNotNull(destination, "parcEventBuffer_ReadIntoBuffer was passed a null destination buffer\n");
+// assertNotNull(destination->evbuffer, "parcEventBuffer_ReadIntoBuffer was passed a null destination evbuffer\n");
+
+ return evbuffer_remove_buffer(source->evbuffer, destination->evbuffer, length);
+}
+
+int
+parcEventBuffer_Read(PARCEventBuffer *readBuffer, void *data, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_Read was passed a null buffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_Read was passed a null libevent evbuffer\n");
+
+ if (data == NULL) {
+ return evbuffer_drain(readBuffer->evbuffer, length);
+ } else {
+ return evbuffer_remove(readBuffer->evbuffer, data, length);
+ }
+}
+
+int
+parcEventBuffer_copyOut(PARCEventBuffer *readBuffer, void *data_out, size_t length)
+{
+ assertNotNull(data_out, "parcEventBuffer_Copy was passed a null data_out buffer\n");
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+ return evbuffer_copyout(readBuffer->evbuffer, data_out, length);
+}
+
+int
+parcEventBuffer_WriteToFileDescriptor(PARCEventBuffer *writeBuffer, int fd, ssize_t length)
+{
+ parcEventBuffer_OptionalAssertValid(writeBuffer);
+
+// assertNotNull(writeBuffer, "parcEventBuffer_WriteToFileDescriptor was passed a null buffer\n");
+// assertNotNull(writeBuffer->evbuffer, "parcEventBuffer_WriteToFileDescriptor was passed a null libevent evbuffer\n");
+
+ return evbuffer_write_atmost(writeBuffer->evbuffer, fd, length);
+}
+
+int
+parcEventBuffer_ReadFromFileDescriptor(PARCEventBuffer *readBuffer, int fd, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_ReadFromFileDescriptor was passed a null buffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_ReadFromFileDescriptor was passed a null libevent evbuffer\n");
+
+ return evbuffer_read(readBuffer->evbuffer, fd, (int) length);
+}
+
+void
+parcEventBuffer_FreeLine(PARCEventBuffer *readBuffer, char **line)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_ReadLine was passed a null readBuffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_ReadLine was passed a null libevent evbuffer\n");
+
+ parcMemory_Deallocate((void **) line);
+}
+
+char *
+parcEventBuffer_ReadLine(PARCEventBuffer *readBuffer, size_t *length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_ReadLine was passed a null readBuffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_ReadLine was passed a null libevent evbuffer\n");
+
+ return evbuffer_readln(readBuffer->evbuffer, length, EVBUFFER_EOL_CRLF);
+}
+
+int
+parcEventBuffer_AppendBuffer(PARCEventBuffer *source, PARCEventBuffer *destination)
+{
+ parcEventBuffer_OptionalAssertValid(source);
+ parcEventBuffer_OptionalAssertValid(destination);
+// assertNotNull(source, "parcEventBuffer_AppendBuffer was passed a null source parcEventBuffer\n");
+// assertNotNull(destination, "parcEventBuffer_AppendBuffer was passed a null destination parcEventBuffer\n");
+// assertNotNull(source->evbuffer, "parcEventBuffer_AppendBuffer was passed a null source libevent evbuffer\n");
+// assertNotNull(destination->evbuffer, "parcEventBuffer_AppendBuffer was passed a null destination libevent evbuffer\n");
+
+ return evbuffer_add_buffer(destination->evbuffer, source->evbuffer);
+}
+
+int
+parcEventBuffer_Append(PARCEventBuffer *parcEventBuffer, void *data, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(parcEventBuffer);
+// assertNotNull(parcEventBuffer, "parcEventBuffer_Append was passed a null parcEventBuffer\n");
+// assertNotNull(parcEventBuffer->evbuffer, "parcEventBuffer_Append was passed a null libevent evbuffer\n");
+ assertNotNull(data, "parcEventBuffer_Append was passed a null data buffer\n");
+
+ return evbuffer_add(parcEventBuffer->evbuffer, data, length);
+}
+
+int
+parcEventBuffer_Prepend(PARCEventBuffer *readBuffer, void *data, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_Prepend was passed a null libevent evbuffer\n");
+// assertNotNull(readBuffer, "parcEventBuffer_Prepend was passed a null buffer\n");
+ assertNotNull(data, "parcEventBuffer_Prepend was passed a null data buffer\n");
+
+ return evbuffer_prepend(readBuffer->evbuffer, data, length);
+}
+
+PARCEventBuffer *
+parcEventBuffer_GetQueueBufferInput(PARCEventQueue *queue)
+{
+ assertNotNull(queue, "parcEventBuffer_GetQueueBufferInput was passed a null queue\n");
+
+ PARCEventBuffer *parcEventBuffer = parcMemory_AllocateAndClear(sizeof(PARCEventBuffer));
+ assertNotNull(parcEventBuffer, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventBuffer));
+
+ parcEventBuffer->evbuffer = internal_parcEventQueue_GetEvInputBuffer(queue);
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_GetQueueBufferInput(queue=%p)\n", queue);
+
+ return parcEventBuffer;
+}
+
+PARCEventBuffer *
+parcEventBuffer_GetQueueBufferOutput(PARCEventQueue *queue)
+{
+ assertNotNull(queue, "parcEventBuffer_GetQueueBufferOutput was passed a null queue\n");
+
+ PARCEventBuffer *parcEventBuffer = parcMemory_AllocateAndClear(sizeof(PARCEventBuffer));
+ assertNotNull(parcEventBuffer, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventBuffer));
+
+ parcEventBuffer->evbuffer = internal_parcEventQueue_GetEvOutputBuffer(queue);
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_GetQueueBufferInput(queue=%p)\n", queue);
+
+ return parcEventBuffer;
+}
+
+void
+parcEventBuffer_EnableDebug(PARCLog *logger)
+{
+ parcEventBufferDebugLog = logger;
+}
+
+void
+parcEventBuffer_DisableDebug(void)
+{
+ parcEventBufferDebugLog = NULL;
+}
diff --git a/libparc/parc/algol/parc_EventBuffer.h b/libparc/parc/algol/parc_EventBuffer.h
new file mode 100755
index 00000000..8e82a5e6
--- /dev/null
+++ b/libparc/parc/algol/parc_EventBuffer.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventBuffer.h
+ * @ingroup events
+ * @brief Buffered event management
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventBuffer_h
+#define libparc_parc_EventBuffer_h
+
+#include <parc/algol/parc_EventQueue.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcEventBuffer_OptionalAssertValid(_instance_)
+#else
+# define parcEventBuffer_OptionalAssertValid(_instance_) parcEventBuffer_AssertValid(_instance_)
+#endif
+
+/**
+ * @typedef PARCEventBuffer
+ * @brief A structure containing private libevent state data variables
+ */
+typedef struct PARCEventBuffer PARCEventBuffer;
+
+/**
+ * Create an event buffer instance.
+ *
+ * @returns A pointer to a new PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ * }
+ * @endcode
+ *
+ */
+PARCEventBuffer *parcEventBuffer_Create(void);
+
+/**
+ * Destroy a network parcEventBuffer instance.
+ *
+ * The address of the event instance is passed in.
+ *
+ * @param [in] parcEventBuffer - The address of the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventBuffer_Destroy(&parcEventBuffer)
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_Destroy(PARCEventBuffer **parcEventBuffer);
+
+/**
+ * Determine if an instance of `PARCEventBuffer` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] eventBuffer A pointer to a `PARCEventBuffer` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *instance = parcEventBuffer_Create();
+ *
+ * if (parcEventBuffer_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcEventBuffer_IsValid(const PARCEventBuffer *eventBuffer);
+
+/**
+ * Assert that the given `PARCEventBuffer` instance is valid.
+ *
+ * @param [in] eventBuffer A pointer to a valid PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *a = parcEventBuffer_Create();
+ *
+ * parcEventBuffer_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcEventBuffer_Release(&b);
+ * }
+ * @endcode
+ */
+void parcEventBuffer_AssertValid(const PARCEventBuffer *eventBuffer);
+
+/**
+ * Get the input parcEventBuffer instance from the Queue
+ *
+ * @param [in] parcEventQueue - The queue to obtain the input parcEventBuffer from
+ * @returns A pointer to the a PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *parcEventBuffer = parcEventBuffer_GetQueueBufferInput(eventQueue);
+ * }
+ * @endcode
+ *
+ */
+PARCEventBuffer *parcEventBuffer_GetQueueBufferInput(PARCEventQueue *parcEventQueue);
+
+/**
+ * Get the output parcEventBuffer instance from the Queue
+ *
+ * @param [in] parcEventQueue - The queue to obtain the output parcEventBuffer from
+ * @returns A pointer to the a PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *parcEventBuffer = parcEventBuffer_GetQueueBufferOutput(parcEventQueue);
+ * }
+ * @endcode
+ *
+ */
+PARCEventBuffer *parcEventBuffer_GetQueueBufferOutput(PARCEventQueue *parcEventQueue);
+
+/**
+ * Get the data length of the associated buffer
+ *
+ * @param [in] parcEventBuffer - The buffer to obtain the length from
+ * @returns The length of data within the buffer, 0 if the internal buffer has been freed
+ *
+ * Example:
+ * @code
+ * {
+ * int length = parcEventBuffer_GetLength(parcEventBuffer);
+ * }
+ * @endcode
+ *
+ */
+size_t parcEventBuffer_GetLength(PARCEventBuffer *parcEventBuffer);
+
+/**
+ * Consolidate data in the associated parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The buffer to consolidate
+ * @param [in] size - The length of data to consolidate, -1 linearizes the entire buffer
+ * @returns A pointer to the first byte in the buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * unsigned char *ptr = parcEventBuffer_Pullup(parcEventBuffer, size);
+ * }
+ * @endcode
+ *
+ */
+uint8_t *parcEventBuffer_Pullup(PARCEventBuffer *parcEventBuffer, ssize_t size);
+
+/**
+ * Read data from the associated parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The parcEventBuffer to read from
+ * @param [in] data - The memory to read into, NULL to discard data
+ * @param [in] length - The number of bytes of data to be read
+ * @returns Number of bytes read, -1 on failure.
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesRead = parcEventBuffer_Read(parcEventBuffer, destination, bytesToRead);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_Read(PARCEventBuffer *parcEventBuffer, void *data, size_t length);
+
+/**
+ * Read data from the associated parcEventBuffer without delete them from the buffer.
+ * Data can not be NULL
+ *
+ * @param [in] parcEventBuffer - The parcEventBuffer to read from
+ * @param [in] data - The memory to read into
+ * @param [in] length - The number of bytes of data to be read
+ * @returns Number of bytes read, -1 on failure.
+ *
+ */
+int parcEventBuffer_copyOut(PARCEventBuffer *readBuffer, void *data_out, size_t length);
+
+
+/**
+ * Read from a file descriptor into the end of a buffer
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] fd - The file descriptor to read from
+ * @param [in] length - The number of bytes of data to be read
+ * @returns The number of bytes read, 0 on EOF and -1 on error.
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesTransfered = parcEventBuffer_ReadFromFileDescriptor(parcEventBuffer, fd, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_ReadFromFileDescriptor(PARCEventBuffer *parcEventBuffer, int fd, size_t length);
+
+/**
+ * Write to a file descriptor from a buffer
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] fd - The file descriptor to write to
+ * @param [in] length - The number of bytes of data to be read (-1 for all).
+ * @returns The number of bytes read, 0 on EOF and -1 on error.
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesTransfered = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fd, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_WriteToFileDescriptor(PARCEventBuffer *parcEventBuffer, int fd, ssize_t length);
+
+/**
+ * Append one PARCEventBuffer to another
+ *
+ * @param [in] source - The buffer to append
+ * @param [in] destination - The buffer to append to
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventBuffer_AppendBuffer(source, destination);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_AppendBuffer(PARCEventBuffer *source, PARCEventBuffer *destination);
+
+/**
+ * Append bytes to a parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The buffer to write into
+ * @param [in] sourceData - The data to append
+ * @param [in] length - The number of bytes of data to be added
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventBuffer_Append(parcEventBuffer, sourceData, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_Append(PARCEventBuffer *parcEventBuffer, void *sourceData, size_t length);
+
+/**
+ * Prepend data to the associated parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The parcEventBuffer to prepend to
+ * @param [in] sourceData - The data to prepend
+ * @param [in] length - The number of bytes of data to be added
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventBuffer_Read(parcEventBuffer, sourceData, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_Prepend(PARCEventBuffer *parcEventBuffer, void *sourceData, size_t length);
+
+/**
+ * Move data from one buffer to another
+ *
+ * @param [in] sourceEventBuffer - The buffer to read from
+ * @param [in] destinationEventBuffer - The buffer to move into
+ * @param [in] length - The number of bytes of data to be moved
+ * @returns The number of bytes moved on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesMoved = parcEventBuffer_Create(sourceEventBuffer, destinationEventBuffer, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_ReadIntoBuffer(PARCEventBuffer *sourceEventBuffer, PARCEventBuffer *destinationEventBuffer, size_t length);
+
+/**
+ * Read a text line terminated by an optional carriage return, followed by a single linefeed
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] length - The number of bytes of data to be moved
+ * @returns A newly allocated null terminated string, which must be freed by the caller
+ *
+ * Example:
+ * @code
+ * {
+ * char *text = parcEventBuffer_ReadLine(parcEventBuffer, length);
+ * ...
+ * parcMemory_Deallocate((void *)&text);
+ * }
+ * @endcode
+ *
+ */
+char *parcEventBuffer_ReadLine(PARCEventBuffer *parcEventBuffer, size_t *length);
+
+/**
+ * Free a text line returned from parcEventBuffer_ReadLine
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] line address of returned value from previous call to parcEventBuffer_ReadLine
+ *
+ * Example:
+ * @code
+ * {
+ * char *text = parcEventBuffer_ReadLine(parcEventBuffer, length);
+ * ...
+ * parcEventBuffer_FreeLine(parcEventBuffer, &text);
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_FreeLine(PARCEventBuffer *parcEventBuffer, char **line);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * @param [in] logger - the log to write debug messages to
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventBuffer_EnableDebug(logger);
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_EnableDebug(PARCLog *logger);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventBuffer_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_DisableDebug(void);
+#endif // libparc_parc_EventBuffer_h
diff --git a/libparc/parc/algol/parc_EventQueue.c b/libparc/parc/algol/parc_EventQueue.c
new file mode 100755
index 00000000..5d656a12
--- /dev/null
+++ b/libparc/parc/algol/parc_EventQueue.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_queue_debug_enabled = 0;
+
+#define parcEventQueue_LogDebug(parcEventQueue, ...) \
+ if (_parc_event_queue_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventQueue->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <event2/buffer.h>
+#include <event2/bufferevent.h>
+
+/**
+ * @typedef PARCEventQueue
+ * @brief A structure containing private event state
+ */
+struct PARCEventQueue {
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ struct bufferevent *buffereventBuffer;
+ // Interpose on bufferevent callbacks
+ PARCEventQueue_Callback *readCallback;
+ void *readUserData;
+ PARCEventQueue_Callback *writeCallback;
+ void *writeUserData;
+ PARCEventQueue_EventCallback *eventCallback;
+ void *eventUserData;
+};
+
+struct PARCEventQueuePair {
+ PARCEventQueue *up;
+ PARCEventQueue *down;
+};
+
+static void
+_parc_queue_read_callback(struct bufferevent *bev, void *ptr)
+{
+ PARCEventQueue *parcEventQueue = (PARCEventQueue *) ptr;
+ parcEventQueue_LogDebug(parcEventQueue,
+ "_parc_queue_read_callback(bev=%p,ptr->buffereventBuffer=%p,parcEventQueue=%p)\n",
+ bev, parcEventQueue->buffereventBuffer, parcEventQueue);
+ assertNotNull(parcEventQueue->readCallback, "parcEvent read callback called when NULL");
+
+ parcEventQueue->readCallback(parcEventQueue, PARCEventType_Read, parcEventQueue->readUserData);
+}
+
+static void
+_parc_queue_write_callback(struct bufferevent *bev, void *ptr)
+{
+ PARCEventQueue *parcEventQueue = (PARCEventQueue *) ptr;
+ parcEventQueue_LogDebug(parcEventQueue,
+ "_parc_queue_write_callback(bev=%p,ptr->buffereventBuffer=%p,parcEventQueue=%p)\n",
+ bev, parcEventQueue->buffereventBuffer, parcEventQueue);
+ assertNotNull(parcEventQueue->writeCallback, "parcEvent write callback called when NULL");
+
+ parcEventQueue->writeCallback(parcEventQueue, PARCEventType_Write, parcEventQueue->writeUserData);
+}
+
+static void
+_parc_queue_event_callback(struct bufferevent *bev, short events, void *ptr)
+{
+ PARCEventQueue *parcEventQueue = (PARCEventQueue *) ptr;
+ int errno_forwarded = errno;
+ parcEventQueue_LogDebug(parcEventQueue,
+ "_parc_queue_event_callback(bev=%p,events=%x,errno=%d,ptr->buffereventBuffer=%p,parcEventQueue=%p)\n",
+ bev, events, errno, parcEventQueue->buffereventBuffer, parcEventQueue);
+ assertNotNull(parcEventQueue->eventCallback, "parcEvent event callback called when NULL");
+
+ errno = errno_forwarded;
+ parcEventQueue->eventCallback(parcEventQueue, internal_bufferevent_type_to_PARCEventQueueEventType(events), parcEventQueue->eventUserData);
+}
+
+void
+parcEventQueue_SetCallbacks(PARCEventQueue *parcEventQueue,
+ PARCEventQueue_Callback *readCallback,
+ PARCEventQueue_Callback *writeCallback,
+ PARCEventQueue_EventCallback *eventCallback,
+ void *user_data)
+{
+ parcEventQueue_LogDebug(parcEventQueue,
+ "parcEventQueue_SetCallbacks(event=%p(buffer=%p),readcb=%p,writecb=%p,eventcb=%p,user_data=%p)\n",
+ parcEventQueue, parcEventQueue->buffereventBuffer,
+ readCallback, writeCallback, eventCallback,
+ user_data);
+
+ parcEventQueue->readCallback = readCallback;
+ parcEventQueue->readUserData = user_data;
+ parcEventQueue->writeCallback = writeCallback;
+ parcEventQueue->writeUserData = user_data;
+ parcEventQueue->eventCallback = eventCallback;
+ parcEventQueue->eventUserData = user_data;
+ bufferevent_setcb(parcEventQueue->buffereventBuffer,
+ (readCallback) ? _parc_queue_read_callback : NULL,
+ (writeCallback) ? _parc_queue_write_callback : NULL,
+ (eventCallback) ? _parc_queue_event_callback : NULL,
+ parcEventQueue);
+}
+
+PARCEventQueue *
+parcEventQueue_Create(PARCEventScheduler *eventScheduler, int fd, PARCEventQueueOption flags)
+{
+ assertNotNull(eventScheduler, "parcEventQueue_Create passed a NULL scheduler instance.");
+ PARCEventQueue *parcEventQueue = parcMemory_AllocateAndClear(sizeof(PARCEventQueue));
+ assertNotNull(parcEventQueue, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueue));
+ parcEventQueue->eventScheduler = eventScheduler;
+
+ //
+ // PARCEventQueue_CloseOnFree
+ // we close the underlying file descriptor/bufferevent/whatever
+ // when this bufferevent is freed.
+ //
+ // PARCEventQueue_DeferCallbacks
+ // callbacks are run deferred in the event loop.
+ //
+ parcEventQueue->buffereventBuffer = bufferevent_socket_new(parcEventScheduler_GetEvBase(eventScheduler), fd,
+ internal_PARCEventQueueOption_to_bufferevent_options(flags));
+ assertNotNull(parcEventQueue->buffereventBuffer,
+ "Got null from bufferevent_socket_new for socket %d", fd);
+
+ parcEventQueue_LogDebug(parcEventQueue,
+ "parcEventQueue_Create(eventScheduler=%p,libevent_base=%p) = %p\n",
+ eventScheduler,
+ parcEventScheduler_GetEvBase(eventScheduler),
+ parcEventQueue);
+
+ return parcEventQueue;
+}
+
+void
+parcEventQueue_Destroy(PARCEventQueue **parcEventQueue)
+{
+ parcEventQueue_LogDebug((*parcEventQueue), "parcEventQueue_Destroy(ptr=%p)\n", *parcEventQueue);
+ assertNotNull((*parcEventQueue)->buffereventBuffer, "parcEventQueue_Destroy passed a null buffer!");
+
+ bufferevent_free((*parcEventQueue)->buffereventBuffer);
+ parcMemory_Deallocate((void *) parcEventQueue);
+}
+
+int
+parcEventQueue_SetFileDescriptor(PARCEventQueue *parcEventQueue, int fd)
+{
+ return bufferevent_setfd(parcEventQueue->buffereventBuffer, fd);
+}
+
+int
+parcEventQueue_GetFileDescriptor(PARCEventQueue *parcEventQueue)
+{
+ return bufferevent_getfd(parcEventQueue->buffereventBuffer);
+}
+
+PARCEventType
+parcEventQueue_GetEnabled(PARCEventQueue *event)
+{
+ return internal_libevent_type_to_PARCEventType(bufferevent_get_enabled(event->buffereventBuffer));
+}
+
+void
+parcEventQueue_Enable(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ bufferevent_enable(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types));
+}
+
+void
+parcEventQueue_Disable(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ bufferevent_disable(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types));
+}
+
+int
+parcEventQueue_ConnectSocket(PARCEventQueue *instance, struct sockaddr *address, int addrlen)
+{
+ return bufferevent_socket_connect(instance->buffereventBuffer, address, addrlen);
+}
+
+int
+parcEventQueue_Flush(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ return bufferevent_flush(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types), BEV_NORMAL);
+}
+
+int
+parcEventQueue_Finished(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ return bufferevent_flush(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types), BEV_FINISHED);
+}
+
+void
+parcEventQueue_SetWatermark(PARCEventQueue *parcEventQueue, PARCEventType types, size_t low, size_t high)
+{
+ parcEventQueue_LogDebug(parcEventQueue, "parcEventQueue->buffereventBuffer=%p\n", parcEventQueue->buffereventBuffer);
+ bufferevent_setwatermark(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types), low, high);
+}
+
+int
+parcEventQueue_Printf(PARCEventQueue *parcEventQueue, const char *fmt, ...)
+{
+ struct evbuffer *buffer = bufferevent_get_output(parcEventQueue->buffereventBuffer);
+ assertNotNull(buffer, "bufferevent_get_output returned NULL");
+
+ va_list ap;
+
+ va_start(ap, fmt);
+ int result = evbuffer_add_vprintf(buffer, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+int
+parcEventQueue_Read(PARCEventQueue *parcEventQueue, void *data, size_t dataLength)
+{
+ return bufferevent_read(parcEventQueue->buffereventBuffer, data, dataLength);
+}
+
+int
+parcEventQueue_Write(PARCEventQueue *parcEventQueue, void *data, size_t dataLength)
+{
+ return bufferevent_write(parcEventQueue->buffereventBuffer, data, dataLength);
+}
+
+int
+parcEventQueue_SetPriority(PARCEventQueue *eventQueue, PARCEventPriority priority)
+{
+ bufferevent_priority_set(eventQueue->buffereventBuffer, internal_PARCEventPriority_to_libevent_priority(priority));
+ return 0;
+}
+
+PARCEventQueuePair *
+parcEventQueue_CreateConnectedPair(PARCEventScheduler *eventScheduler)
+{
+ assertNotNull(eventScheduler, "parcEventQueue_CreateConnectedPair must be passed a valid Event Scheduler");
+ PARCEventQueuePair *parcEventQueuePair = parcMemory_AllocateAndClear(sizeof(PARCEventQueuePair));
+ assertNotNull(parcEventQueuePair, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueuePair));
+
+ parcEventQueuePair->up = parcMemory_AllocateAndClear(sizeof(PARCEventQueue));
+ parcEventQueuePair->up->eventScheduler = eventScheduler;
+ parcEventQueue_LogDebug(parcEventQueuePair->up,
+ "up instance parcEventQueue_Create(eventScheduler=%p,libevent_parcEventQueue=%p) = %p\n",
+ eventScheduler,
+ parcEventScheduler_GetEvBase(eventScheduler),
+ parcEventQueuePair->up);
+ assertNotNull(parcEventQueuePair->up, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueue));
+
+ parcEventQueuePair->down = parcMemory_AllocateAndClear(sizeof(PARCEventQueue));
+ parcEventQueuePair->down->eventScheduler = eventScheduler;
+ parcEventQueue_LogDebug(parcEventQueuePair->down,
+ "down instance parcEventQueue_Create(eventScheduler=%p,libevent_parcEventQueue=%p) = %p\n",
+ eventScheduler,
+ parcEventScheduler_GetEvBase(eventScheduler),
+ parcEventQueuePair->down);
+ assertNotNull(parcEventQueuePair->down, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueue));
+
+ struct bufferevent *evpair[2];
+ int result = bufferevent_pair_new(parcEventScheduler_GetEvBase(eventScheduler), 0, evpair);
+ if (result != 0) {
+ parcMemory_Deallocate((void **) &(parcEventQueuePair->up));
+ parcMemory_Deallocate((void **) &(parcEventQueuePair->down));
+ parcMemory_Deallocate((void **) &parcEventQueuePair);
+ return NULL;
+ }
+
+ parcEventQueuePair->up->buffereventBuffer = evpair[0];
+ parcEventQueuePair->down->buffereventBuffer = evpair[1];
+
+ (void) parcEventQueue_SetPriority(parcEventQueuePair->up, PARCEventPriority_Normal);
+ (void) parcEventQueue_SetPriority(parcEventQueuePair->down, PARCEventPriority_Normal);
+
+ return parcEventQueuePair;
+}
+
+void
+parcEventQueue_DestroyConnectedPair(PARCEventQueuePair **queuePair)
+{
+ parcEventQueue_LogDebug((*queuePair)->up,
+ "parcEventQueue_DestroyPair(up ptr=%p)\n",
+ (*queuePair)->up);
+ parcEventQueue_LogDebug((*queuePair)->down,
+ "parcEventQueue_DestroyPair(down ptr=%p)\n",
+ (*queuePair)->down);
+
+ bufferevent_free((*queuePair)->up->buffereventBuffer);
+ bufferevent_free((*queuePair)->down->buffereventBuffer);
+
+ parcMemory_Deallocate((void **) &((*queuePair)->up));
+ parcMemory_Deallocate((void **) &((*queuePair)->down));
+ parcMemory_Deallocate((void **) queuePair);
+}
+
+PARCEventQueue *
+parcEventQueue_GetConnectedUpQueue(PARCEventQueuePair *queuePair)
+{
+ return queuePair->up;
+}
+
+PARCEventQueue *
+parcEventQueue_GetConnectedDownQueue(PARCEventQueuePair *queuePair)
+{
+ return queuePair->down;
+}
+
+struct evbuffer *
+internal_parcEventQueue_GetEvInputBuffer(PARCEventQueue *queue)
+{
+ return bufferevent_get_input(queue->buffereventBuffer);
+}
+
+struct evbuffer *
+internal_parcEventQueue_GetEvOutputBuffer(PARCEventQueue *queue)
+{
+ return bufferevent_get_output(queue->buffereventBuffer);
+}
+
+void
+parcEventQueue_EnableDebug(void)
+{
+ _parc_event_queue_debug_enabled = 1;
+}
+
+void
+parcEventQueue_DisableDebug(void)
+{
+ _parc_event_queue_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventQueue.h b/libparc/parc/algol/parc_EventQueue.h
new file mode 100644
index 00000000..282df302
--- /dev/null
+++ b/libparc/parc/algol/parc_EventQueue.h
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventQueue.h
+ * @ingroup events
+ * @brief Queue buffer events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventQueue_h
+#define libparc_parc_EventQueue_h
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <parc/algol/parc_Event.h>
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+/**
+ * @typedef PARCEventQueue
+ * @brief A structure containing private libevent state data variables
+ */
+typedef struct PARCEventQueue PARCEventQueue;
+
+/**
+ * @typedef PARCEventQueuePair
+ * @brief A structure containing private libevent state data for connected queue pairs
+ */
+typedef struct PARCEventQueuePair PARCEventQueuePair;
+
+/**
+ * @typedef PARCEventQueueEventType
+ * @brief An enumeration of queue event types
+ */
+typedef enum {
+ PARCEventQueueEventType_Reading = 0x01,
+ PARCEventQueueEventType_Writing = 0x02,
+ PARCEventQueueEventType_EOF = 0x10,
+ PARCEventQueueEventType_Error = 0x20,
+ PARCEventQueueEventType_Timeout = 0x40,
+ PARCEventQueueEventType_Connected = 0x80
+} PARCEventQueueEventType;
+
+/**
+ * @typedef PARCEventQueue_Options
+ * @brief A structure queue flags
+ */
+typedef enum {
+ PARCEventQueueOption_CloseOnFree = 0x01,
+ PARCEventQueueOption_DeferCallbacks = 0x04
+} PARCEventQueueOption;
+
+/**
+ * @typedef PARCEventQueue_Callback
+ * @brief A definition for callback function arguments
+ */
+typedef void (PARCEventQueue_Callback)(PARCEventQueue *event, PARCEventType type, void *user_data);
+
+/**
+ * @typedef PARCEventQueue_EventCallback
+ * @brief A definition for callback function arguments
+ */
+typedef void (PARCEventQueue_EventCallback)(PARCEventQueue *event, PARCEventQueueEventType type, void *user_data);
+
+/**
+ * Create a buffer event handler instance.
+ *
+ * The event instance is passed in. Options can be either, both or none of the following.
+ *
+ * PARCEventQueue_CloseOnFree
+ * The underlying file descriptor is closed when this event is freed.
+ *
+ * PARCEventQueue_DeferCallbacks
+ * Callbacks are run deferred in the scheduler.
+ *
+ * @param [in] eventScheduler - The scheduler instance base.
+ * @param [in] fd the file descriptor to monitor
+ * @param [in] options as described in flags above
+ * @returns A pointer to the a PARCEventQueue instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueue *event = parcEventQueue_Create(eventScheduler, fd, PARCEventQueue_CloseOnFree);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueue *parcEventQueue_Create(PARCEventScheduler *eventScheduler, int fd, PARCEventQueueOption options);
+
+/**
+ * Destroy a buffer event handler instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] eventQueue - The address of the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Destroy(&eventQueue);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_Destroy(PARCEventQueue **eventQueue);
+
+/**
+ * Enable events on an instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] event - queue instance to enable.
+ * @param [in] types - the event(s) to enable.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Enable(bufferEvent, PARCEvent_ReadEvent);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_Enable(PARCEventQueue *event, PARCEventType types);
+
+/**
+ * Get enable events on an instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue - the instance to return enabled events from
+ * @returns mask of events which are enabled.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventType *events = parcEventQueue_GetEnable(queue);
+ * }
+ * @endcode
+ *
+ */
+PARCEventType parcEventQueue_GetEnabled(PARCEventQueue *queue);
+
+/**
+ * Disable events on an instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue - instance to disable event on.
+ * @param [in] types - the events to disable.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Disable(queue, types);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_Disable(PARCEventQueue *queue, PARCEventType types);
+
+/**
+ * Set callbacks on a buffer event instance.
+ *
+ * The event instance is passed in.
+ * You can disable a callback by passing NULL instead of the callback function.
+ * NB: all the callback functions on a bufferevent share a single user_data
+ * value, so changing user_data will affect all of them.
+ *
+ * @param [in] eventInstance - event instance
+ * @param [in] readCallback - callback for read events
+ * @param [in] writeCallback - callback for write events
+ * @param [in] eventCallback - callback for non-read/write events
+ * @param [in] user_data - data passed along in callback arguments
+ *
+ * Example:
+ * @code
+ * void Callback(PARCEventType type, void *user_data)
+ * {
+ * printf("Received event of type=%d\n", type);
+ * }
+ * ...
+ * {
+ * ...
+ * parcEventQueue_SetCallbacks(eventInstance, Callback, NULL, NULL, user_data);
+ * parcEventQueue_Enable(eventInstance, PARCEventType_Read);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_SetCallbacks(PARCEventQueue *eventInstance,
+ PARCEventQueue_Callback *readCallback,
+ PARCEventQueue_Callback *writeCallback,
+ PARCEventQueue_EventCallback *eventCallback,
+ void *user_data);
+
+/**
+ * Flush events on a queue
+ *
+ * @param [in] queue instance to flush
+ * @param [in] types the type(s) of events to flush
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Flush(queue, PARCEventType_Write);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Flush(PARCEventQueue *queue, PARCEventType types);
+
+/**
+ * Finialized flush of events on a queue
+ *
+ * @param [in] queue instance to flush
+ * @param [in] types the type(s) of events to flush
+ * @returns 0 if no data was flushed, 1 if some data was flushed, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Finished(queue, PARCEventType_Write);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Finished(PARCEventQueue *queue, PARCEventType types);
+
+/**
+ * Set watermark boundries on a queue
+ *
+ * @param [in] queue - queue instance to set watermark on
+ * @param [in] types - the events to set watermark on
+ * @param [in] low - the low watermark value
+ * @param [in] high - the high watermark value
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_SetWatermark(queue, PARCEventType_Read, 0, MAXPATHLEN);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_SetWatermark(PARCEventQueue *queue, PARCEventType types, size_t low, size_t high);
+
+/**
+ * Add formatted text to the end of a queue
+ *
+ * @param [in] queue - queue instance to write to
+ * @param [in] fmt - printf arguments
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Printf(queue, "%s\n", "Hello world.");
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Printf(PARCEventQueue *queue, const char *fmt, ...);
+
+/**
+ * Set the associated file descriptor on a queue
+ *
+ * @param [in] queue instance set to monitor this descriptor
+ * @param [in] fd file descriptor
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_SetFileDescriptor(queue, STDIN_FILENO);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_SetFileDescriptor(PARCEventQueue *queue, int fd);
+
+/**
+ * Get the associated file descriptor on a queue
+ *
+ * @param [in] queue instance set to monitor this descriptor
+ * @returns file descriptor on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int fileDescriptor = parcEventQueue_GetFileDescriptor(queue);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_GetFileDescriptor(PARCEventQueue *queue);
+
+/**
+ * Read data from the queue output
+ *
+ * @param [in] queue instance to read from
+ * @param [in] data to read into
+ * @param [in] dataLength length of data to read
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Read(queue, data, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Read(PARCEventQueue *queue, void *data, size_t dataLength);
+
+/**
+ * Add data to the queue output
+ *
+ * @param [in] queue instance to add to
+ * @param [in] data to write
+ * @param [in] dataLength length of data to write
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Write(queue, data, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Write(PARCEventQueue *queue, void *data, size_t dataLength);
+
+/**
+ * Attach an launch a socket on a queue
+ *
+ * @param [in] queue instance to attach socket to
+ * @param [in] address socket data
+ * @param [in] addressLength socket data length
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_un addr_unix;
+ * memset(&addr_unix, 0, sizeof(addr_unix));
+ * addr_unix.sun_family = AF_UNIX;
+ * strcpy(addr_unix.sun_path, sock_name);
+ * int result = parcEventQueue_ConnectSocket(queue, addr_unix, sizeof(addr_unix));
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_ConnectSocket(PARCEventQueue *queue, struct sockaddr *address, int addressLength);
+
+/**
+ * Set queue priority
+ *
+ * @param [in] queue instance to modify
+ * @param [in] priority queue priority
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_Enable(queue, PARCEventQueuePriority_Normal);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_SetPriority(PARCEventQueue *queue, PARCEventPriority priority);
+
+/**
+ * Create a pair of connected queues
+ *
+ * @param [in] eventScheduler event scheduler instance
+ * @returns a queue pair instance
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueuePair *pair = parcEventQueue_CreateConnectedPair(eventScheduler);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueuePair *parcEventQueue_CreateConnectedPair(PARCEventScheduler *eventScheduler);
+
+/**
+ * Destroy a connected queue pair
+ *
+ * @param [in] queuePair queue pair instance address to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueuePairCreateparcEventQueue_DestroyConnectedPair(&queuePair);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_DestroyConnectedPair(PARCEventQueuePair **queuePair);
+
+/**
+ * Return the downward queue of a pair
+ *
+ * @param [in] queuePair queue pair instance address to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueue *downQueue = parcEventQueue_GetConnectedDownQueue(queuePair);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueue *parcEventQueue_GetConnectedDownQueue(PARCEventQueuePair *queuePair);
+
+/**
+ * Return the upward queue of a pair
+ *
+ * @param [in] queuePair queue pair instance address to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueue *upQueue = parcEventQueue_GetConnectedUpQueue(queuePair);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueue *parcEventQueue_GetConnectedUpQueue(PARCEventQueuePair *queuePair);
+
+/**
+ * Private Internal Function - return internal input buffer of a queue
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue the event queue
+ * @returns private evbuffer pointer
+ *
+ * Example:
+ * @code
+ * {
+ * struct evbuffer *evbuffer = internal_parcEventQueue_GetEvInputBuffer(queue);
+ * }
+ * @endcode
+ *
+ */
+struct evbuffer *internal_parcEventQueue_GetEvInputBuffer(PARCEventQueue *queue);
+
+/**
+ * Private Internal Function - return internal output buffer of a queue
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue the event queue
+ * @returns private evbuffer pointer
+ *
+ * Example:
+ * @code
+ * {
+ * struct evbuffer *evbuffer = internal_parcEventQueue_GetEvOutputBuffer(queue);
+ * }
+ * @endcode
+ *
+ */
+struct evbuffer *internal_parcEventQueue_GetEvOutputBuffer(PARCEventQueue *queue);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_DisableDebug(void);
+#endif // libparc_parc_EventQueue_h
diff --git a/libparc/parc/algol/parc_EventScheduler.c b/libparc/parc/algol/parc_EventScheduler.c
new file mode 100755
index 00000000..55de5c52
--- /dev/null
+++ b/libparc/parc/algol/parc_EventScheduler.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+
+static int _parc_event_scheduler_debug_enabled = 0;
+
+#define parcEventScheduler_LogDebug(parcEventScheduler, ...) \
+ if (_parc_event_scheduler_debug_enabled) \
+ parcLog_Debug(parcEventScheduler->log, __VA_ARGS__)
+
+struct PARCEventScheduler {
+ /**
+ * Base of the libevent manager.
+ */
+ struct event_base *evbase;
+ PARCLog *log;
+};
+
+static PARCLog *
+_parc_logger_create(void)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create("localhost", "test_parc_Log", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ parcLog_SetLevel(log, PARCLogLevel_All);
+ return log;
+}
+
+void *
+parcEventScheduler_GetEvBase(PARCEventScheduler *parcEventScheduler)
+{
+ return (void *) parcEventScheduler->evbase;
+}
+
+PARCEventScheduler *
+parcEventScheduler_Create(void)
+{
+ internal_parc_initializeLibevent();
+
+ PARCEventScheduler *parcEventScheduler = parcMemory_Allocate(sizeof(PARCEventScheduler));
+ assertNotNull(parcEventScheduler, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventScheduler));
+
+ // Initialize libevent base pointer.
+ parcEventScheduler->evbase = event_base_new();
+
+ assertNotNull(parcEventScheduler->evbase, "Could not obtain an event base!");
+ int result = event_base_priority_init(parcEventScheduler->evbase, PARCEventPriority_NumberOfPriorities);
+ assertTrue(result == 0, "Could not set scheduler priorities (%d)", result);
+
+ parcEventScheduler->log = _parc_logger_create();
+ assertNotNull(parcEventScheduler->log, "Could not create parc logger");
+
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Create() = %p\n", parcEventScheduler);
+
+ return parcEventScheduler;
+}
+
+int
+parcEventScheduler_Start(PARCEventScheduler *parcEventScheduler, PARCEventSchedulerDispatchType type)
+{
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Start(%p, %d)\n", parcEventScheduler, type);
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Start must be passed a valid base parcEventScheduler!");
+ int result = event_base_loop(parcEventScheduler->evbase,
+ internal_PARCEventSchedulerDispatchType_to_eventloop_options(type));
+ return result;
+}
+
+int
+parcEventScheduler_DispatchBlocking(PARCEventScheduler *parcEventScheduler)
+{
+ return parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+}
+
+int
+parcEventScheduler_DispatchNonBlocking(PARCEventScheduler *parcEventScheduler)
+{
+ return parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking);
+}
+
+int
+parcEventScheduler_Stop(PARCEventScheduler *parcEventScheduler, struct timeval *delay)
+{
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Stop(%p, %p)\n", parcEventScheduler, delay);
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Stop must be passed a valid base parcEventScheduler!");
+ int result = event_base_loopexit(parcEventScheduler->evbase, delay);
+ return result;
+}
+
+int
+parcEventScheduler_Abort(PARCEventScheduler *parcEventScheduler)
+{
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Abort(%p)\n", parcEventScheduler);
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Abort must be passed a valid base parcEventScheduler!");
+ int result = event_base_loopbreak(parcEventScheduler->evbase);
+ return result;
+}
+
+static int _event_enable_debug_mode_called = 0;
+
+void
+parcEventScheduler_EnableDebug(void)
+{
+ _parc_event_scheduler_debug_enabled = 1;
+ if (_event_enable_debug_mode_called == 0) {
+ event_enable_debug_mode();
+ _event_enable_debug_mode_called = 1;
+ }
+}
+
+void
+parcEventScheduler_DisableDebug(void)
+{
+ _parc_event_scheduler_debug_enabled = 0;
+}
+
+void
+parcEventScheduler_Destroy(PARCEventScheduler **parcEventScheduler)
+{
+ parcEventScheduler_LogDebug((*parcEventScheduler), "parcEventScheduler_Destroy(%p)\n", *parcEventScheduler);
+
+ assertNotNull(*parcEventScheduler, "parcEventScheduler_Destroy must be passed a valid base parcEventScheduler!");
+ assertNotNull((*parcEventScheduler)->evbase, "parcEventScheduler_Destroy passed a NULL event base member!");
+
+ event_base_free((*parcEventScheduler)->evbase);
+ parcLog_Release(&((*parcEventScheduler)->log));
+ parcMemory_Deallocate((void **) parcEventScheduler);
+}
+
+PARCLog *
+parcEventScheduler_GetLogger(PARCEventScheduler *parcEventScheduler)
+{
+ return parcEventScheduler->log;
+}
diff --git a/libparc/parc/algol/parc_EventScheduler.h b/libparc/parc/algol/parc_EventScheduler.h
new file mode 100644
index 00000000..d84ac5e4
--- /dev/null
+++ b/libparc/parc/algol/parc_EventScheduler.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventScheduler.h
+ * @ingroup events
+ * @brief Event scheduler
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventScheduler_h
+#define libparc_parc_EventScheduler_h
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/*
+ * Currently implemented using libevent
+ */
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/logging/parc_Log.h>
+
+/**
+ * @typedef PARCEventScheduler
+ * @brief A structure containing private event state
+ */
+struct PARCEventScheduler;
+typedef struct PARCEventScheduler PARCEventScheduler;
+
+typedef enum {
+ PARCEventSchedulerDispatchType_Blocking = 0x00,
+ PARCEventSchedulerDispatchType_LoopOnce = 0x01,
+ PARCEventSchedulerDispatchType_NonBlocking = 0x02,
+} PARCEventSchedulerDispatchType;
+
+/**
+ * Create a new parcEventScheduler instance.
+ *
+ * A new parcEventScheduler instance is returned.
+ *
+ * @returns A pointer to the a PARCEvent instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEvent *parcEventScheduler = parcEvent_Create();
+ * }
+ * @endcode
+ *
+ */
+PARCEventScheduler *parcEventScheduler_Create(void);
+
+/**
+ * Start the event eventScheduler
+ *
+ * @param [in] parcEventScheduler - The parcEventScheduler instance to start.
+ * @param type - The mode of dispatch for this `PARCEventScheduler` instance.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_Start(parcEventScheduler, PARCEventScheduler_Blocking);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_Start(PARCEventScheduler *parcEventScheduler, PARCEventSchedulerDispatchType type);
+
+/**
+ * Dispatch the event scheduler to process any pending events, blocking until
+ * some events have been triggered and then processed.
+ *
+ * @param [in] parcEventScheduler - The parcEventScheduler instance to run.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_DispatchBlocking(parcEventScheduler, PARCEventScheduler_Blocking);
+ * }
+ * @endcode
+ */
+int parcEventScheduler_DispatchBlocking(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Dispatch the event scheduler to process any pending events.
+ *
+ * If there are no pending events then the function will immediately return.
+ *
+ * @param [in] parcEventScheduler - The parcEventScheduler instance to run.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_DispatchNonBlocking(parcEventScheduler, PARCEventScheduler_Blocking);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_DispatchNonBlocking(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Stop the event parcEventScheduler
+ *
+ * @param [in] parcEventScheduler instance to stop scheduling.
+ * @param [in] delay time to wait before stopping, 0 for stop now
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_Stop(parcEventScheduler, timeout);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_Stop(PARCEventScheduler *parcEventScheduler, struct timeval *delay);
+
+/**
+ * Immediately abort the event parcEventScheduler
+ *
+ * @param [in] parcEventScheduler instance to abort scheduling.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_Abort(parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_Abort(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Destroy a parcEventScheduler instance.
+ *
+ * The address of the parcEventScheduler instance is passed in.
+ *
+ * @param [in] parcEventScheduler address of instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_Destroy(&parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+void parcEventScheduler_Destroy(PARCEventScheduler **parcEventScheduler);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventScheduler_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventScheduler_DisableDebug(void);
+
+/**
+ * Internal libevent data accessor function.
+ *
+ * THIS IS FOR INTERNAL USE ONLY. USE WITH CAUTION.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_GetEvBase(parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+void *parcEventScheduler_GetEvBase(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Logger accessor function
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLog *logger = parcEventScheduler_GetLogger(parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+PARCLog *parcEventScheduler_GetLogger(PARCEventScheduler *parcEventScheduler);
+#endif // libparc_parc_EventScheduler_h
diff --git a/libparc/parc/algol/parc_EventSignal.c b/libparc/parc/algol/parc_EventSignal.c
new file mode 100755
index 00000000..7b8d1191
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSignal.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventSignal.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_signal_debug_enabled = 0;
+
+#define parcEventSignal_LogDebug(parcEventSignal, ...) \
+ if (_parc_event_signal_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventSignal->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+#include <event2/util.h>
+
+struct PARCEventSignal {
+ /**
+ * The event instance.
+ */
+ struct event *event;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ PARCEventSignal_Callback *callback;
+ void *callbackUserData;
+};
+
+static void
+_parc_event_signal_callback(evutil_socket_t fd, short flags, void *context)
+{
+ PARCEventSignal *parcEventSignal = (PARCEventSignal *) context;
+ parcEventSignal_LogDebug(parcEventSignal,
+ "_parc_event_signal_callback(fd=%x,flags=%x,parcEventSignal=%p)\n",
+ fd, flags, parcEventSignal);
+ parcEventSignal->callback((int) fd, internal_libevent_type_to_PARCEventType(flags),
+ parcEventSignal->callbackUserData);
+}
+
+PARCEventSignal *
+parcEventSignal_Create(PARCEventScheduler *eventScheduler, int signal, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs)
+{
+ PARCEventSignal *parcEventSignal = parcMemory_Allocate(sizeof(PARCEventSignal));
+ assertNotNull(parcEventSignal, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventSignal));
+
+ parcEventSignal->eventScheduler = eventScheduler;
+ parcEventSignal->callback = callback;
+ parcEventSignal->callbackUserData = callbackArgs;
+
+ parcEventSignal->event = event_new(parcEventScheduler_GetEvBase(eventScheduler), signal,
+ internal_PARCEventType_to_libevent_type(flags),
+ _parc_event_signal_callback, parcEventSignal);
+ assertNotNull(parcEventSignal->event, "Could not create a new event!");
+
+ parcEventSignal_LogDebug(parcEventSignal,
+ "parcEventSignal_Create(base=%p,signal=%x,flags=%x,cb=%p,args=%p) = %p\n",
+ parcEventScheduler_GetEvBase(eventScheduler), signal, flags,
+ callback, callbackArgs, parcEventSignal);
+ return parcEventSignal;
+}
+
+int
+parcEventSignal_Start(PARCEventSignal *parcEventSignal)
+{
+ parcEventSignal_LogDebug(parcEventSignal, "parcEventSignal_Start(event=%p)\n", parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEventStart_Signal must be passed a valid event!");
+
+ int result = event_add(parcEventSignal->event, NULL);
+ return result;
+}
+
+int
+parcEventSignal_Stop(PARCEventSignal *parcEventSignal)
+{
+ parcEventSignal_LogDebug(parcEventSignal, "parcEventSignal_Stop(event=%p)\n", parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEvent_Stop must be passed a valid event!");
+
+ int result = event_del(parcEventSignal->event);
+ return result;
+}
+
+void
+parcEventSignal_Destroy(PARCEventSignal **parcEventSignal)
+{
+ parcEventSignal_LogDebug((*parcEventSignal), "parcEventSignal_Destroy(event=%p)\n", parcEventSignal);
+ assertNotNull(*parcEventSignal, "parcEvent_Destroy must be passed a valid parcEventSignal!");
+ assertNotNull((*parcEventSignal)->event, "parcEvent_Destroy passed a null event!");
+ event_free((*parcEventSignal)->event);
+ parcMemory_Deallocate((void **) parcEventSignal);
+}
+
+void
+parcEventSignal_EnableDebug(void)
+{
+ _parc_event_signal_debug_enabled = 1;
+}
+
+void
+parcEventSignal_DisableDebug(void)
+{
+ _parc_event_signal_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventSignal.h b/libparc/parc/algol/parc_EventSignal.h
new file mode 100755
index 00000000..e289f506
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSignal.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventSignal.h
+ * @ingroup events
+ * @brief Signal events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventSignal
+#define libparc_parc_EventSignal
+
+#include <parc/algol/parc_Event.h>
+
+typedef void (PARCEventSignal_Callback)(int fd, PARCEventType type, void *user_data);
+
+typedef struct PARCEventSignal PARCEventSignal;
+
+/**
+ * Create a new signal event instance.
+ *
+ * The new event instance is returned.
+ *
+ * @param [in] parcEventScheduler - scheduler instance
+ * @param [in] signal - signal to catch
+ * @param [in] flags - event flags
+ * @param [in] callback - event callback
+ * @param [in] callbackArguments - private arguments passed to callback
+ * @returns A pointer to the a PARCEventSignal instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, 0, callback, callbackArguments);
+ * }
+ * @endcode
+ *
+ */
+PARCEventSignal *parcEventSignal_Create(PARCEventScheduler *parcEventScheduler,
+ int signal, PARCEventType flags,
+ PARCEventSignal_Callback *callback,
+ void *callbackArguments);
+
+/**
+ * Prepare a parcEventSignal instance to be scheduled.
+ *
+ * @returns -1 on error, 0 on success if nothing changed in the event backend, and 1 on success if something did.
+ * @param [in] parcEventSignal the newly created event instance.
+ *
+ * Example:
+ * @code
+ * addEvent(PARCEventSignal *parcEventSignal)
+ * {
+ * int result = parcEventSignal_Start(parcEventSignal);
+ * }
+ * @endcode
+ *
+ */
+int parcEventSignal_Start(PARCEventSignal *parcEventSignal);
+
+/**
+ * Stop a parcEventSignal instance.
+ *
+ * @param [in] parcEventSignal - The newly created event instance.
+ *
+ * Example:
+ * @code
+ * removeEvent(PARCEventSignal *parcEventSignal)
+ * {
+ * parcEventSignal_Stop(parcEventSignal);
+ * }
+ * @endcode
+ *
+ */
+int parcEventSignal_Stop(PARCEventSignal *parcEventSignal);
+
+/**
+ * Destroy a parcEventSignal instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventSignal The instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSignal_Destroy(&eparcEventSignal vent);
+ * }
+ * @endcode
+ *
+ */
+void parcEventSignal_Destroy(PARCEventSignal **parcEventSignal);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSignal_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSignal_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSignal_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSignal_DisableDebug(void);
+#endif // libparc_parc_EventSignal_h
diff --git a/libparc/parc/algol/parc_EventSocket.c b/libparc/parc/algol/parc_EventSocket.c
new file mode 100755
index 00000000..dcb2fd69
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSocket.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventSocket.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_socket_debug_enabled = 0;
+
+#define parcEventSocket_LogDebug(parcEventSocket, ...) \
+ if (_parc_event_socket_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventSocket->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <sys/errno.h>
+#include <event2/listener.h>
+
+/**
+ * @typedef PARCEventSocket
+ * @brief A structure containing private event state
+ */
+struct PARCEventSocket {
+ struct evconnlistener *listener;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ // Interpose on EventSocket callbacks
+ PARCEventSocket_Callback *socketCallback;
+ void *socketUserData;
+ PARCEventSocket_ErrorCallback *socketErrorCallback;
+ void *socketErrorUserData;
+};
+
+static void
+_parc_evconn_callback(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *address, int socklen, void *ctx)
+{
+ PARCEventSocket *parcEventSocket = (PARCEventSocket *) ctx;
+ parcEventSocket_LogDebug(parcEventSocket, "_parc_evconn_callback(fd=%d,,parcEventSocket=%p)\n", fd, parcEventSocket);
+
+ parcEventSocket->socketCallback((int) fd, address, socklen, parcEventSocket->socketUserData);
+}
+
+static void
+_parc_evconn_error_callback(struct evconnlistener *listener, void *ctx)
+{
+ PARCEventSocket *parcEventSocket = (PARCEventSocket *) ctx;
+
+ int error = EVUTIL_SOCKET_ERROR();
+ char *errorString = evutil_socket_error_to_string(error);
+ parcEventSocket_LogDebug(parcEventSocket,
+ "_parc_evconn_error_callback(error=%d,errorString=%s,parcEventSocket=%p)\n",
+ error, errorString, parcEventSocket);
+
+ parcEventSocket->socketErrorCallback(parcEventSocket->eventScheduler,
+ error, errorString, parcEventSocket->socketErrorUserData);
+}
+
+PARCEventSocket *
+parcEventSocket_Create(PARCEventScheduler *eventScheduler,
+ PARCEventSocket_Callback *callback,
+ PARCEventSocket_ErrorCallback *errorCallback,
+ void *userData, const struct sockaddr *sa, int socklen)
+{
+ PARCEventSocket *parcEventSocket = parcMemory_AllocateAndClear(sizeof(PARCEventSocket));
+ assertNotNull(parcEventSocket, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventSocket));
+
+ parcEventSocket->eventScheduler = eventScheduler;
+ parcEventSocket->socketCallback = callback;
+ parcEventSocket->socketErrorCallback = errorCallback;
+ parcEventSocket->socketUserData = userData;
+ parcEventSocket->socketErrorUserData = userData;
+ parcEventSocket->listener = evconnlistener_new_bind(parcEventScheduler_GetEvBase(eventScheduler),
+ _parc_evconn_callback, parcEventSocket,
+ LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
+ sa, socklen);
+ if (parcEventSocket->listener == NULL) {
+ parcLog_Error(parcEventScheduler_GetLogger(eventScheduler),
+ "Libevent evconnlistener_new_bind error (%d): %s",
+ errno, strerror(errno));
+ parcEventSocket_Destroy(&parcEventSocket);
+ return NULL;
+ }
+
+ if (errorCallback) {
+ evconnlistener_set_error_cb(parcEventSocket->listener, _parc_evconn_error_callback);
+ }
+ parcEventSocket_LogDebug(parcEventSocket,
+ "parcEventSocket_Create(cb=%p,args=%p) = %p\n",
+ callback, userData, parcEventSocket);
+ return parcEventSocket;
+}
+
+void
+parcEventSocket_Destroy(PARCEventSocket **socketEvent)
+{
+ assertNotNull(*socketEvent, "parcEventSocket_Destroy must be passed a valid socketEvent!");
+
+ if ((*socketEvent)->listener) {
+ evconnlistener_free((*socketEvent)->listener);
+ }
+ parcEventSocket_LogDebug((*socketEvent), "parcEventSocket_Destroy(%p)\n", *socketEvent);
+ parcMemory_Deallocate((void **) socketEvent);
+}
+
+void
+parcEventSocket_EnableDebug(void)
+{
+ _parc_event_socket_debug_enabled = 1;
+}
+
+void
+parcEventSocket_DisableDebug(void)
+{
+ _parc_event_socket_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventSocket.h b/libparc/parc/algol/parc_EventSocket.h
new file mode 100755
index 00000000..48a11b25
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSocket.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventSocket.h
+ * @ingroup events
+ * @brief Socket events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventSocket_h
+#define libparc_parc_EventSocket_h
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Event.h>
+
+typedef struct PARCEventSocket PARCEventSocket;
+
+typedef void (PARCEventSocket_Callback)(int fd, struct sockaddr *address,
+ int socklen, void *user_data);
+typedef void (PARCEventSocket_ErrorCallback)(PARCEventScheduler *,
+ int error, char *errorString,
+ void *user_data);
+
+/**
+ * Create a socket event handler instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventScheduler the scheduler instance
+ * @param [in] callback the callback function.
+ * @param [in] errorCallback the error callback function.
+ * @param [in] userData pointer to private arguments for instance callback function
+ * @param [in] sa is the socket address to bind to (INET, INET6, LOCAL)
+ * @param [in] socklen is the sizeof the actual sockaddr (e.g. sizeof(sockaddr_un))
+ * @returns A pointer to a new PARCEventSocket instance.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ */
+PARCEventSocket *parcEventSocket_Create(PARCEventScheduler *parcEventScheduler,
+ PARCEventSocket_Callback *callback,
+ PARCEventSocket_ErrorCallback *errorCallback,
+ void *userData,
+ const struct sockaddr *sa, int socklen);
+
+/**
+ * Destroy a socket event handler instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventSocket the address of the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEvent *event = parcEventSocket_Destroy(&parcEventSocket);
+ * }
+ * @endcode
+ *
+ */
+void parcEventSocket_Destroy(PARCEventSocket **parcEventSocket);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSocket_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSocket_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSocket_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSocket_DisableDebug(void);
+#endif // libparc_parc_EventSocket_h
diff --git a/libparc/parc/algol/parc_EventTimer.c b/libparc/parc/algol/parc_EventTimer.c
new file mode 100755
index 00000000..529188b1
--- /dev/null
+++ b/libparc/parc/algol/parc_EventTimer.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventTimer.h>
+
+static int _parc_event_timer_debug_enabled = 0;
+
+#define parcEventTimer_LogDebug(parcEventTimer, ...) \
+ if (_parc_event_timer_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventTimer->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+#include <event2/util.h>
+
+struct PARCEventTimer {
+ /**
+ * The event instance.
+ */
+ struct event *event;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ PARCEventTimer_Callback *callback;
+ void *callbackUserData;
+};
+
+static void
+_parc_event_timer_callback(evutil_socket_t fd, short flags, void *context)
+{
+ PARCEventTimer *parcEventTimer = (PARCEventTimer *) context;
+ parcEventTimer_LogDebug(parcEventTimer,
+ "_parc_event_timer_callback(fd=%x,flags=%x,parcEventTimer=%p)\n",
+ fd, flags, parcEventTimer);
+ parcEventTimer->callback((int) fd, internal_libevent_type_to_PARCEventType(flags),
+ parcEventTimer->callbackUserData);
+}
+
+PARCEventTimer *
+parcEventTimer_Create(PARCEventScheduler *eventScheduler, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs)
+{
+ PARCEventTimer *parcEventTimer = parcMemory_Allocate(sizeof(PARCEventTimer));
+ assertNotNull(parcEventTimer, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventTimer));
+
+ parcEventTimer->eventScheduler = eventScheduler;
+ parcEventTimer->callback = callback;
+ parcEventTimer->callbackUserData = callbackArgs;
+
+ // NB: the EV_TIMEOUT flag is ignored when constructing an event
+ parcEventTimer->event = event_new(parcEventScheduler_GetEvBase(eventScheduler), -1,
+ internal_PARCEventType_to_libevent_type(flags),
+ _parc_event_timer_callback, parcEventTimer);
+ assertNotNull(parcEventTimer->event, "Could not create a new event!");
+
+ parcEventTimer_LogDebug(parcEventTimer,
+ "parcEventTimer_Create(base=%p,events=%x,cb=%p,args=%p) = %p\n",
+ parcEventScheduler_GetEvBase(eventScheduler), flags,
+ callback, callbackArgs, parcEventTimer);
+
+ return parcEventTimer;
+}
+
+int
+parcEventTimer_Start(PARCEventTimer *parcEventTimer, struct timeval *timeout)
+{
+ parcEventTimer_LogDebug(parcEventTimer,
+ "parcEventTimer_Start(event=%p, timeout=%d:%d)\n",
+ parcEventTimer, timeout->tv_sec, timeout->tv_usec);
+ assertNotNull(parcEventTimer, "parcEventTimer_Start must be passed a valid event!");
+
+ int result = event_add(parcEventTimer->event, timeout);
+ return result;
+}
+
+int
+parcEventTimer_Stop(PARCEventTimer *parcEventTimer)
+{
+ parcEventTimer_LogDebug(parcEventTimer, "parcEventTimer_Stop(event=%p)\n", parcEventTimer);
+ assertNotNull(parcEventTimer, "parcEventTimer_Stop must be passed a valid event!");
+
+ int result = event_del(parcEventTimer->event);
+ return result;
+}
+
+void
+parcEventTimer_Destroy(PARCEventTimer **parcEventTimer)
+{
+ parcEventTimer_LogDebug((*parcEventTimer), "parcEventTimer_Destroy(parcEventTimer=%p)\n", *parcEventTimer);
+ assertNotNull(*parcEventTimer, "parcEventTimer_Destroy must be passed a valid parcEventTimer!");
+ assertNotNull((*parcEventTimer)->event, "parcEventTimer_Destroy passed a null event!");
+
+ event_free((*parcEventTimer)->event);
+ parcMemory_Deallocate((void **) parcEventTimer);
+}
+
+void
+parcEventTimer_EnableDebug(void)
+{
+ _parc_event_timer_debug_enabled = 1;
+}
+
+void
+parcEventTimer_DisableDebug(void)
+{
+ _parc_event_timer_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventTimer.h b/libparc/parc/algol/parc_EventTimer.h
new file mode 100755
index 00000000..4a960853
--- /dev/null
+++ b/libparc/parc/algol/parc_EventTimer.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_EventTimer.h
+ * @ingroup events
+ * @brief Timer events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventTimer_h
+#define libparc_parc_EventTimer_h
+
+#include <parc/algol/parc_Event.h>
+
+typedef void (PARCEventTimer_Callback)(int fd, PARCEventType type, void *user_data);
+
+typedef struct PARCEventTimer PARCEventTimer;
+
+/**
+ * Create a new timer event instance.
+ *
+ * The new event instance is returned.
+ *
+ * @param [in] parcEventScheduler - scheduler instance to attach to
+ * @param [in] flags - event flags
+ * @param [in] callback - timer callback function
+ * @param [in] callbackArguments - private arguments passed to callback
+ * @returns A pointer to the a PARCEventTimer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventTimer *event = parcEvent_Create(parcEventScheduler, PARCEvent_None, callback, callbackArguments);
+ * }
+ * @endcode
+ *
+ */
+PARCEventTimer *parcEventTimer_Create(PARCEventScheduler *parcEventScheduler,
+ PARCEventType flags,
+ PARCEventTimer_Callback *callback,
+ void *callbackArguments);
+
+/**
+ * Position a timer event instance to be scheduled.
+ *
+ * @param [in] parcEventTimer - The newly created event instance and a timeout value.
+ * @param [in] timeout - time to wait for event, or NULL to wait forever.
+ * @returns -1 on error, 0 on success if nothing changed in the event backend, and 1 on success if something did.
+ *
+ * Example:
+ * @code
+ * addEvent(PARCEventTimer *parcEventTimer)
+ * {
+ * struct timeval timeout = {5, 0};
+ * int result = parcEventTimer_Start(parcEventTimer, &timeout);
+ * }
+ * @endcode
+ *
+ */
+int parcEventTimer_Start(PARCEventTimer *parcEventTimer, struct timeval *timeout);
+
+/**
+ * Stop a timer event instance.
+ *
+ * @param [in] parcEventTimer - The newly created event instance and a timeout value.
+ * @returns 0 on success
+ *
+ * Example:
+ * @code
+ * removeEvent(PARCEventTimer *parcEventTimer)
+ * {
+ * parcEventTimer_Stop(parcEventTimer);
+ * }
+ * @endcode
+ *
+ */
+int parcEventTimer_Stop(PARCEventTimer *parcEventTimer);
+
+/**
+ * Destroy an event instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventTimer the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventTimer_Destroy(&parcEventTimer);
+ * }
+ * @endcode
+ *
+ */
+void parcEventTimer_Destroy(PARCEventTimer **parcEventTimer);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventTimer_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventTimer_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventTimer_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventTimer_DisableDebug(void);
+#endif // libparc_parc_EventTimer_h
diff --git a/libparc/parc/algol/parc_Execution.c b/libparc/parc/algol/parc_Execution.c
new file mode 100644
index 00000000..8b31dcdb
--- /dev/null
+++ b/libparc/parc/algol/parc_Execution.c
@@ -0,0 +1,97 @@
+//
+// parc_Status.c
+// Libparc
+//
+//
+//
+#include <config.h>
+#include <stdio.h>
+
+#include "parc_Execution.h"
+
+/*
+ * A PARCExecution value is a unique thing which can have a string assigned to it.
+ *
+ * I want the function to be:
+ *
+ * A thing that returns an Execution
+ *
+ * Execution function() { }
+ *
+ * A thing that an Execution value can be
+ *
+ * Execution value = function;
+ */
+
+struct PARCExecution {
+ struct PARCExecution (*type)(char *format, ...);
+ char *message;
+};
+
+PARCExecution *PARCExecution_OK = &(PARCExecution) {
+ .message = "OK"
+};
+
+PARCExecution *PARCExecution_Timeout = &(PARCExecution) {
+ .message = "Timeout"
+};
+
+PARCExecution *PARCExecution_Interrupted = &(PARCExecution) {
+ .message = "Interrupted"
+};
+
+PARCExecution *PARCExecution_IOError = &(PARCExecution) {
+ .message = "I/O Error"
+};
+
+PARCExecution *
+parcExecution_OK(const char *format, ...)
+{
+ return PARCExecution_OK;
+}
+
+PARCExecution *
+parcExecution_Interrupted(const char *format, ...)
+{
+ return PARCExecution_Interrupted;
+}
+
+PARCExecution *
+parcExecution_IOError(const char *format, ...)
+{
+ return PARCExecution_IOError;
+}
+
+bool
+parcExecution_Is(const PARCExecution *exec, const PARCExecution *other)
+{
+ return (exec == other);
+}
+
+char *
+parcExecution_GetMessage(const PARCExecution *exec)
+{
+ return exec->message;
+}
+
+PARCExecution *
+bar()
+{
+ return PARCExecution_OK;
+}
+
+PARCExecution *
+baz()
+{
+ return parcExecution_OK("Nothing to say");
+}
+
+void
+foo()
+{
+ PARCExecution *x = bar();
+ PARCExecution *y = baz();
+
+ printf("%s\n", parcExecution_GetMessage(x));
+ printf("%s\n", parcExecution_GetMessage(y));
+}
diff --git a/libparc/parc/algol/parc_Execution.h b/libparc/parc/algol/parc_Execution.h
new file mode 100644
index 00000000..1aadc589
--- /dev/null
+++ b/libparc/parc/algol/parc_Execution.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Execution.h
+ * @ingroup datastructures
+ * @brief PARC Execution Status
+ * An extensible set of status values used to communicate
+ * out-of-band or exceptional conditions as return values.
+ *
+ */
+#ifndef parc_Execution_h
+#define parc_Execution_h
+
+#include <stdbool.h>
+
+struct PARCExecution;
+typedef struct PARCExecution PARCExecution;
+
+extern PARCExecution *PARCExecution_OK;
+extern PARCExecution *PARCExecution_Interrupted;
+extern PARCExecution *PARCExecution_IOError;
+extern PARCExecution *PARCExecution_Timeout;
+
+char *parcExecution_GetMessage(const PARCExecution *exec);
+
+bool parcExecution_Is(const PARCExecution *exec, const PARCExecution *other);
+
+#endif /* parc_Status_h */
diff --git a/libparc/parc/algol/parc_File.c b/libparc/parc/algol/parc_File.c
new file mode 100644
index 00000000..2ab307a2
--- /dev/null
+++ b/libparc/parc/algol/parc_File.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 500
+#endif //_XOPEN_SOURCE 500
+
+#ifndef __USE_XOPEN_EXTENDED
+#define __USE_XOPEN_EXTENDED
+#endif //__USE_XOPEN_EXTENDED
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+
+#include <ftw.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <string.h>
+#include <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_PathName.h>
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_Memory.h>
+
+
+struct parc_file {
+ PARCPathName *pathName;
+};
+
+static bool
+_parcFile_Destructor(PARCFile **filePtr)
+{
+ PARCFile *file = *filePtr;
+
+ parcPathName_Release(&file->pathName);
+
+ return true;
+}
+
+parcObject_Override(PARCFile, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcFile_Destructor,
+ .toString = (PARCObjectToString *) parcFile_ToString);
+
+void
+parcFile_AssertValid(const PARCFile *instance)
+{
+ trapIllegalValueIf(instance == NULL, "Parameter must be a non-null pointer to a valid PARCFile.");
+ trapIllegalValueIf(instance->pathName == NULL, "PARCFile cannot have a NULL path-name");
+}
+
+PARCFile *
+parcFile_Create(const char *path)
+{
+ PARCFile *result = NULL;
+
+ PARCPathName *pathName = parcPathName_Parse(path);
+ if (pathName != NULL) {
+ result = parcObject_CreateInstance(PARCFile);
+ if (result != NULL) {
+ result->pathName = pathName;
+ } else {
+ parcPathName_Release(&pathName);
+ }
+ }
+
+ return result;
+}
+
+PARCFile *
+parcFile_CreateChild(const PARCFile *parent, char *fileName)
+{
+ PARCFile *result = NULL;
+
+ PARCPathName *childPath = parcPathName_Append(parcPathName_Copy(parent->pathName), fileName);
+
+ if (childPath != NULL) {
+ result = parcObject_CreateInstance(PARCFile);
+ if (result != NULL) {
+ result->pathName = childPath;
+ }
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcFile, PARCFile);
+
+parcObject_ImplementRelease(parcFile, PARCFile);
+
+bool
+parcFile_CreateNewFile(const PARCFile *file)
+{
+ parcFile_OptionalAssertValid(file);
+
+ bool result = false;
+
+ char *string = parcPathName_ToString(file->pathName);
+
+ int fd = open(string, O_EXCL | O_CREAT | O_TRUNC, 0666);
+ if (fd != -1) {
+ close(fd);
+ result = true;
+ }
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+bool
+parcFile_Mkdir(const PARCFile *file)
+{
+ parcFile_OptionalAssertValid(file);
+
+ char *string = parcPathName_ToString(file->pathName);
+ bool result = (mkdir(string, 0777) == 0);
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+bool
+parcFile_Exists(const PARCFile *file)
+{
+ struct stat statbuf;
+
+ char *string = parcPathName_ToString(file->pathName);
+ bool result = stat(string, &statbuf) == 0;
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+bool
+parcFile_IsDirectory(const PARCFile *file)
+{
+ bool result = false;
+ struct stat statbuf;
+
+ char *string = parcPathName_ToString(file->pathName);
+ if (stat(string, &statbuf) == 0) {
+ result = S_ISDIR(statbuf.st_mode);
+ }
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+static int
+_deleteNode(const char *path, const struct stat *stat, int flag, struct FTW *ftwbuf)
+{
+ int result = 0;
+
+ if (flag == FTW_DP) { // directory in post-order
+ result = rmdir(path);
+ } else {
+ result = unlink(path);
+ }
+ return result;
+}
+
+/**
+ * @function parcFile_Delete
+ * @abstract Deletes the file or directory
+ * @discussion
+ *
+ * @param <#param1#>
+ * @return true if everything deleted, false otherwise
+ */
+bool
+parcFile_Delete(const PARCFile *file)
+{
+ char *string = parcPathName_ToString(file->pathName);
+
+ // only allow under tmp
+ assertTrue(strncmp(string, "/tmp/", 5) == 0,
+ "Path must begin with /tmp/: %s", string);
+ // dont allow ".."
+ assertNull(strstr(string, ".."), "Path cannot have .. in it: %s", string);
+
+ bool result = false;
+ if (parcFile_IsDirectory(file)) {
+ // depth first, dont't follow symlinks, do not cross mount points.
+ int flags = FTW_DEPTH | FTW_PHYS | FTW_MOUNT;
+
+ // maximum 20 fds open at a time
+ int maximumFileDescriptors = 20;
+
+ int failure = nftw(string, _deleteNode, maximumFileDescriptors, flags);
+ assertFalse(failure, "Error on recursive delete: (%d) %s", errno, strerror(errno));
+
+ result = failure == false;
+ } else {
+ result = (unlink(string) == 0);
+ }
+
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+PARCBufferComposer *
+parcFile_BuildString(const PARCFile *file, PARCBufferComposer *composer)
+{
+ parcPathName_BuildString(file->pathName, composer);
+
+ return composer;
+}
+
+char *
+parcFile_ToString(const PARCFile *file)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcFile_BuildString(file, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+size_t
+parcFile_GetFileSize(const PARCFile *file)
+{
+ size_t fileSize = 0;
+
+ char *fname = parcPathName_ToString(file->pathName);
+
+ struct stat st;
+
+ if (stat(fname, &st) == 0) {
+ fileSize = st.st_size;
+ }
+
+ parcMemory_Deallocate(&fname);
+
+ return fileSize;
+}
diff --git a/libparc/parc/algol/parc_File.h b/libparc/parc/algol/parc_File.h
new file mode 100755
index 00000000..42ef232e
--- /dev/null
+++ b/libparc/parc/algol/parc_File.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_File.h
+ * @ingroup inputoutput
+ * @brief File manipulation
+ *
+ *
+ */
+#ifndef libparc_parc_File_h
+#define libparc_parc_File_h
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcFile_OptionalAssertValid(_instance_)
+#else
+# define parcFile_OptionalAssertValid(_instance_) parcFile_AssertValid(_instance_)
+#endif
+
+struct parc_file;
+typedef struct parc_file PARCFile;
+
+/**
+ * Creates a `PARCFile` object named by pathname.
+ *
+ * This operation does not imply any I/O operations.
+ * The PARCFile instance only represents the pathname,
+ * and does not necessarily reference a real file.
+ *
+ * @param [in] pathname is a pointer to a char array (string)
+ * @return A pointer to an instance of `PARCFile`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCFile *parcFile_Create(const char *pathname);
+
+/**
+ * Acquire a new reference to an instance of `PARCFile`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] file The instance of `PARCFile` to which to refer.
+ *
+ * @return The same value as the input parameter @p file
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFile *parcFile_Acquire(const PARCFile *file);
+
+/**
+ * Assert that an instance of `PARCFile` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a `PARCFile` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/foo");
+ *
+ * parcFile_AssertValid(file);
+ * }
+ * @endcode
+ */
+void parcFile_AssertValid(const PARCFile *instance);
+
+/**
+ * Release a `PARCFile` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCFile`.
+ *
+ * @param [in,out] filePtr is a pointer to the `PARCFile` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcFile_Release(PARCFile **filePtr);
+
+/**
+ * Create a new file on storage.
+ *
+ * @param [in] file A pointer to an instance of `PARCFile`
+ *
+ * @return true if succesful, false if not
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFile_CreateNewFile(const PARCFile *file);
+
+/**
+ * Return true if the PARCFile exists on storage.
+ *
+ * If the pathname can be stat(2)'d, then it exists.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance.
+ * @return true if the file exists, false otherwise
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcFile_Exists(const PARCFile *file);
+
+/**
+ * Create a new directory.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance.
+ * @return true if the pathname exists, false otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFile_Mkdir(const PARCFile *file);
+
+/**
+ * True if the specified `PARCFile` is an existing directory on storage.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance.
+ *
+ * @return true if specified `PARCFile` is an existing directory on storage, false if not
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFile_IsDirectory(const PARCFile *file);
+
+/**
+ * Deletes the file or directory on storage.
+ *
+ * For a directory, it does a recursive delete.
+ *
+ * @param [in] file The instance of `PARCFile` to be deleted.
+ * @return `true` if everything deleted, false otherwise
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcFile_Delete(const PARCFile *file);
+
+/**
+ * Append a representation of the specified `PARCFile` instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] file A pointer to the `PARCFile` instance whose contents should be appended to to string.
+ * @param [in,out] string A pointer to the `PARCBufferComposer` instance to which the contents of file will be appended.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The instance of `PARCBufferComposer` with the appended contents.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ * PARCFile *instance = parcFile_Create("/tmp/foo");
+ *
+ * parcFile_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("File: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcFile_BuildString(const PARCFile *file, PARCBufferComposer *string);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t parcFile_GetFileSize(const PARCFile *file);
+
+/**
+ * Create a PARCFile representation of the home directory of the current user.
+ *
+ * The return value must be released via `parcFile_Release`.
+ *
+ * @return non-NULL A pointer to a valid PARCFile instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *directory = parcFile_CreateHome();
+ * }
+ * @endcode
+ */
+PARCFile *parcFile_CreateHome(void);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCFile` instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] file A pointer to the `PARCFile` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *instance = parcFile_Create("/tmp/foo");
+ *
+ * char *string = parcFile_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcFile_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see {@link parcFile_BuildString}
+ */
+char *parcFile_ToString(const PARCFile *file);
+#endif // libparc_parc_File_h
diff --git a/libparc/parc/algol/parc_FileChunker.c b/libparc/parc/algol/parc_FileChunker.c
new file mode 100644
index 00000000..d7acd58e
--- /dev/null
+++ b/libparc/parc/algol/parc_FileChunker.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_RandomAccessFile.h>
+
+#include <parc/algol/parc_FileChunker.h>
+
+PARCChunkerInterface *PARCFileChunkerAsChunker = &(PARCChunkerInterface) {
+ .ForwardIterator = (void *(*)(const void *))parcFileChunker_ForwardIterator,
+ .ReverseIterator = (void *(*)(const void *))parcFileChunker_ReverseIterator,
+ .GetChunkSize = (size_t (*)(const void *))parcFileChunker_GetChunkSize
+};
+
+struct _parc_chunker_state {
+ size_t chunkNumber;
+ int direction;
+ bool atEnd;
+ size_t position;
+ size_t nextChunkSize;
+ size_t totalSize;
+};
+
+typedef struct _parc_chunker_state _ChunkerState;
+
+struct parc_buffer_chunker {
+ // State
+ size_t chunkSize;
+
+ // Container for the data to be parsed
+ PARCFile *file;
+ PARCRandomAccessFile *fhandle;
+
+ // The current element of the iterator
+ PARCBuffer *currentElement;
+};
+
+static void
+_destroy(PARCFileChunker **chunkerP)
+{
+ if ((*chunkerP)->fhandle != NULL) {
+ parcRandomAccessFile_Release(&(*chunkerP)->fhandle);
+ }
+
+ if ((*chunkerP)->file != NULL) {
+ parcFile_Release(&(*chunkerP)->file);
+ }
+
+ if ((*chunkerP)->currentElement != NULL) {
+ parcBuffer_Release(&(*chunkerP)->currentElement);
+ }
+}
+
+static void *
+_InitForward(PARCFileChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 0;
+ state->position = 0;
+ state->atEnd = false;
+ state->totalSize = parcFile_GetFileSize(chunker->file);
+
+ if (state->totalSize < chunker->chunkSize) {
+ state->position = 0;
+ state->nextChunkSize = state->totalSize;
+ } else {
+ state->position = 0;
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static void *
+_InitReverse(PARCFileChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 1;
+ state->atEnd = false;
+ state->totalSize = parcFile_GetFileSize(chunker->file);
+
+ if (state->totalSize < chunker->chunkSize) {
+ state->position = 0;
+ state->nextChunkSize = state->totalSize;
+ } else {
+ state->position = state->totalSize - chunker->chunkSize;
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static bool
+_parcChunker_HasNext(PARCFileChunker *chunker, void *voidstate)
+{
+ _ChunkerState *state = (_ChunkerState *) voidstate;
+ return !state->atEnd;
+}
+
+static void
+_advanceStateForward(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ state->position += state->nextChunkSize;
+ size_t remaining = state->totalSize - state->position;
+
+ if (remaining == 0) {
+ state->atEnd = true;
+ } else if (remaining > chunker->chunkSize) {
+ state->nextChunkSize = chunker->chunkSize;
+ } else {
+ state->nextChunkSize = remaining;
+ }
+}
+
+static void
+_advanceStateBackward(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ // Previous chunk size
+ size_t chunkSize = state->nextChunkSize;
+ if (chunkSize != chunker->chunkSize || state->position == 0) {
+ state->atEnd = true;
+ } else {
+ if (state->position < chunkSize) {
+ state->nextChunkSize = state->position; // on next read, go to the current position
+ state->position = 0; // we reached the beginning
+ } else {
+ state->position -= chunkSize;
+ }
+ }
+}
+
+static void
+_advanceState(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ state->chunkNumber++;
+
+ if (state->direction == 0) {
+ _advanceStateForward(chunker, state);
+ } else {
+ _advanceStateBackward(chunker, state);
+ }
+}
+
+static void *
+_parcChunker_NextFromBuffer(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ size_t chunkSize = state->nextChunkSize;
+
+ parcRandomAccessFile_Seek(chunker->fhandle, state->position, PARCRandomAccessFilePosition_Start);
+
+ PARCBuffer *slice = parcBuffer_Allocate(chunkSize);
+ parcRandomAccessFile_Read(chunker->fhandle, slice);
+ slice = parcBuffer_Flip(slice);
+
+ _advanceState(chunker, state);
+
+ return slice;
+}
+
+static void *
+_parcChunker_Next(PARCFileChunker *chunker, void *state)
+{
+ PARCBuffer *buffer = _parcChunker_NextFromBuffer(chunker, state);
+
+ if (chunker->currentElement != NULL) {
+ parcBuffer_Release(&chunker->currentElement);
+ }
+ if (buffer != NULL) {
+ chunker->currentElement = parcBuffer_Acquire(buffer);
+ }
+
+ return state;
+}
+
+static void
+_parcChunker_RemoveAt(PARCFileChunker *chunker, void **state)
+{
+ // pass
+}
+
+static void *
+_parcChunker_GetElement(PARCFileChunker *chunker, void *state)
+{
+ return chunker->currentElement;
+}
+
+static void
+_parcChunker_Finish(PARCFileChunker *chunker, void *state)
+{
+ _ChunkerState *thestate = (_ChunkerState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static void
+_parcChunker_AssertValid(const void *state)
+{
+ // pass
+}
+
+parcObject_ExtendPARCObject(PARCFileChunker, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(parcFileChunker, PARCFileChunker);
+parcObject_ImplementRelease(parcFileChunker, PARCFileChunker);
+
+PARCFileChunker *
+parcFileChunker_Create(PARCFile *file, size_t chunkSize)
+{
+ PARCFileChunker *chunker = parcObject_CreateInstance(PARCFileChunker);
+
+ if (chunker != NULL) {
+ chunker->chunkSize = chunkSize;
+ chunker->file = parcFile_Acquire(file);
+ chunker->fhandle = parcRandomAccessFile_Open(chunker->file);
+ chunker->currentElement = NULL;
+ }
+
+ return chunker;
+}
+
+
+PARCIterator *
+parcFileChunker_ForwardIterator(const PARCFileChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_parcChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_parcChunker_Next,
+ (void (*)(PARCObject *, void **))_parcChunker_RemoveAt,
+ (void *(*)(PARCObject *, void *))_parcChunker_GetElement,
+ (void (*)(PARCObject *, void *))_parcChunker_Finish,
+ (void (*)(const void *))_parcChunker_AssertValid);
+
+ return iterator;
+}
+
+PARCIterator *
+parcFileChunker_ReverseIterator(const PARCFileChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitReverse,
+ (bool (*)(PARCObject *, void *))_parcChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_parcChunker_Next,
+ (void (*)(PARCObject *, void **))_parcChunker_RemoveAt,
+ (void *(*)(PARCObject *, void *))_parcChunker_GetElement,
+ (void (*)(PARCObject *, void *))_parcChunker_Finish,
+ (void (*)(const void *))_parcChunker_AssertValid);
+
+ return iterator;
+}
+
+size_t
+parcFileChunker_GetChunkSize(const PARCFileChunker *chunker)
+{
+ return chunker->chunkSize;
+}
diff --git a/libparc/parc/algol/parc_FileChunker.h b/libparc/parc/algol/parc_FileChunker.h
new file mode 100755
index 00000000..6ab0d267
--- /dev/null
+++ b/libparc/parc/algol/parc_FileChunker.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_FileChunker.h
+ * @ingroup ContentObject
+ * @brief A FileChunker is a chunker that segments the content of a file.
+ *
+ */
+
+#ifndef libparc_parc_FileChunker_h
+#define libparc_parc_FileChunker_h
+
+#include <parc/algol/parc_Chunker.h>
+
+#include <parc/algol/parc_File.h>
+
+struct parc_buffer_chunker;
+/**
+ * @typedef PARCFileChunker
+ * @brief The PARC Chunker
+ */
+typedef struct parc_buffer_chunker PARCFileChunker;
+
+/**
+ * The mapping of a `PARCFileChunker` to the generic `PARCChunker`.
+ */
+extern PARCChunkerInterface *PARCFileChunkerAsChunker;
+
+/**
+ * Create a new chunker to segment data contained in a `PARCBuffer.`
+ *
+ * @param [in] file A `PARCFile` from which the data will be read.
+ * @param [in] chunkSize The size per chunk.
+ *
+ * @retval PARCFileChunker A newly allocated `PARCFileChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCFileChunker *chunker = PARCFileChunker_CreateFromBuffer(dataToChunk, 32);
+ * }
+ */
+PARCFileChunker *parcFileChunker_Create(PARCFile *file, size_t chunkSize);
+
+/**
+ * Increase the number of references to a `PARCFileChunker` instance.
+ *
+ * Note that new `PARCFileChunker` is not created,
+ * only that the given `PARCFileChunker` reference count is incremented.
+ * Discard the reference by invoking {@link PARCFileChunker_Release}.
+ *
+ * @param [in] chunker A pointer to the original `PARCFileChunker`.
+ * @return The value of the input parameter @p chunker.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileChunker *original = parcFileChunker_Create(...);
+ *
+ * PARCFileChunker *reference = parcFileChunker_Acquire(original);
+ *
+ * parcFileChunker_Release(&original);
+ * parcFileChunker_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcFileChunker_Release
+ */
+PARCFileChunker *parcFileChunker_Acquire(const PARCFileChunker *chunker);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] chunkerP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCFileChunker *chunker = parcFileChunker_Acquire(instance);
+ *
+ * parcFileChunker_Release(&chunker);
+ * }
+ * @endcode
+ */
+void parcFileChunker_Release(PARCFileChunker **chunkerP);
+
+/**
+ * Determine if two `PARCFileChunker` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCFileChunker` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcFileChunker_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcFileChunker_Equals(x, y)` must return true if and only if
+ * `parcFileChunker_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcFileChunker_Equals(x, y)` returns true and
+ * `parcFileChunker_Equals(y, z)` returns true,
+ * then `parcFileChunker_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcFileChunker_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcFileChunker_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param chunkerA A pointer to a `PARCFileChunker` instance.
+ * @param chunkerB A pointer to a `PARCFileChunker` instance.
+ * @return true if the two `PARCFileChunker` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * char *fileToChunk = ...
+ * PARCFileChunker *chunkerA = parcFileChunker_Create(fileToChunk, 32);
+ * PARCFileChunker *chunkerB = parcFileChunker_Create(fileToChunk, 32);
+ *
+ * bool equals = parcFileChunker_Equals(chunkerA, chunkerB);
+ * }
+ * @endcode
+ */
+bool parcFileChunker_Equals(const PARCFileChunker *chunkerA, const PARCFileChunker *chunkerB);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCFileChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * char *fileToChunk = ...
+ * PARCFileChunker *chunker = parcFileChunker_Create(fileToChunk, 32);
+ *
+ * PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcFileChunker_ForwardIterator(const PARCFileChunker *chunker);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCFileChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * char *fileToChunk = ...
+ * PARCFileChunker *chunker = parcFileChunker_Create(fileToChunk, 32);
+ *
+ * PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcFileChunker_ReverseIterator(const PARCFileChunker *chunker);
+
+/**
+ * Get the chunk size of a `PARCFileChunker.`
+ *
+ * @param [in] chunker A `PARCFileChunker` instance.
+ *
+ * @return the chunk size
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCFileChunker *chunker = ...
+ *
+ * size_t chunkSize = parcFileChunker_GetChunkSize(chunker);
+ * }
+ * @endcode
+ */
+size_t parcFileChunker_GetChunkSize(const PARCFileChunker *chunker);
+#endif // libparc_parc_FileChunker_h
diff --git a/libparc/parc/algol/parc_FileInputStream.c b/libparc/parc/algol/parc_FileInputStream.c
new file mode 100755
index 00000000..f42ced73
--- /dev/null
+++ b/libparc/parc/algol/parc_FileInputStream.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_InputStream.h>
+#include <parc/algol/parc_FileInputStream.h>
+#include <parc/algol/parc_Object.h>
+
+PARCInputStreamInterface *PARCFileInputStreamAsPARCInputStream = &(PARCInputStreamInterface) {
+ .Acquire = (PARCInputStream * (*)(const PARCInputStream *))parcFileInputStream_Acquire,
+ .Release = (void (*)(PARCInputStream **))parcFileInputStream_Release,
+ .Read = (size_t (*)(PARCInputStream *, PARCBuffer *))parcFileInputStream_Read
+};
+
+struct parc_file_input_stream {
+ int fd;
+};
+
+static void
+_destroy(PARCFileInputStream **inputStreamPtr)
+{
+ PARCFileInputStream *inputStream = *inputStreamPtr;
+
+ close(inputStream->fd);
+}
+
+parcObject_ExtendPARCObject(PARCFileInputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCFileInputStream *
+parcFileInputStream_Open(const PARCFile *file)
+{
+ PARCFileInputStream *result = NULL;
+
+ char *fileName = parcFile_ToString(file);
+ if (fileName != NULL) {
+ result = parcFileInputStream_Create(open(fileName, O_RDONLY));
+ parcMemory_Deallocate((void **) &fileName);
+ }
+
+ return result;
+}
+
+PARCFileInputStream *
+parcFileInputStream_Create(int fileDescriptor)
+{
+ trapIllegalValueIf(fileDescriptor < 0, "File descriptor must not be negative.");
+
+ PARCFileInputStream *result = parcObject_CreateInstance(PARCFileInputStream);
+ if (result != NULL) {
+ result->fd = fileDescriptor;
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcFileInputStream, PARCFileInputStream);
+parcObject_ImplementRelease(parcFileInputStream, PARCFileInputStream);
+
+bool
+parcFileInputStream_Read(PARCFileInputStream *inputStream, PARCBuffer *buffer)
+{
+ while (parcBuffer_HasRemaining(buffer)) {
+ void *buf = parcBuffer_Overlay(buffer, 0);
+ ssize_t nread = read(inputStream->fd, buf, parcBuffer_Remaining(buffer));
+ if (nread < 0) {
+ break;
+ }
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + nread);
+ }
+ return parcBuffer_HasRemaining(buffer);
+}
+
+PARCBuffer *
+parcFileInputStream_ReadFile(PARCFileInputStream *inputStream)
+{
+ PARCBuffer *result = NULL;
+
+ struct stat statbuf;
+
+ if (fstat(inputStream->fd, &statbuf) == 0) {
+ result = parcBuffer_Allocate(statbuf.st_size);
+ if (result != NULL) {
+ parcFileInputStream_Read(inputStream, result);
+ }
+ }
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_FileInputStream.h b/libparc/parc/algol/parc_FileInputStream.h
new file mode 100755
index 00000000..3641e08a
--- /dev/null
+++ b/libparc/parc/algol/parc_FileInputStream.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_FileInputStream.h
+ * @ingroup inputoutput
+ * @brief A FileInputStream obtains input bytes from a file in a file system.
+ *
+ * What files are available depends on the host environment.
+ * FileInputStream is meant for reading streams of raw bytes such as image data.
+ *
+ */
+
+#ifndef libparc_parc_FileInputStream_h
+#define libparc_parc_FileInputStream_h
+
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_InputStream.h>
+
+struct parc_file_input_stream;
+
+/**
+ * @typedef PARCFileInputStream
+ * @brief Read streams of input
+ */
+
+typedef struct parc_file_input_stream PARCFileInputStream;
+
+/**
+ * The mapping of a `PARCFileInputStream` to the generic `PARCInputStream`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCInputStreamInterface *PARCFileInputStreamAsPARCInputStream;
+
+/**
+ * Create a `PARCFileInputStream` instance.
+ *
+ * @param [in] fileDescriptor An abstract indicator for accessing a specific file
+ *
+ * @return non-NULL A pointer to an instance of `PARCFileInputStream`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileInputStream *parcFileInputStream_Create(int fileDescriptor);
+
+/**
+ * Create a `PARCFileInputStream` instance by opening an existing {@link PARCFile} instance.
+ *
+ * The file specified by `PARCFile` must exist and readable.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance representing the existing file.
+ *
+ * @return non-NULL A pointer to a `PARCFileInputStream` instance.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileInputStream *parcFileInputStream_Open(const PARCFile *file);
+
+/**
+ * Acquire a new reference to an instance of `PARCFileInputStream`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] inputStream The instance of `PARCFileInputStream` to which to refer.
+ *
+ * @return The same value as the input parameter @p inputStream
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileInputStream *parcFileInputStream_Acquire(const PARCFileInputStream *inputStream);
+
+/**
+ * Release a `PARCFileInputStream` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCFileInputStream`.
+ *
+ * @param [in,out] inputStreamPtr is a pointer to the `PARCFileInputStream` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+void parcFileInputStream_Release(PARCFileInputStream **inputStreamPtr);
+
+/**
+ * Read a `PARCFileInputStream` into a {@link PARCBuffer}.
+ *
+ * The contents of the `PARCBuffer` are filled from the current position to the limit.
+ * When this function returns, the position is set to the end of the last successfully read byte of data.
+ *
+ * @param [in] inputStream The `PARCInputStream` to read.
+ * @param [in] buffer The `PARCBuffer` to read, from the current position of the buffer to its limit.
+ *
+ * @return true The entire contents of the `PARCBuffer`, from the current position to the limit, were filled.
+ * @return false The entire contents of the `PARCBuffer` were not filled.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *stream =
+ * parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT|O_WRONLY|O_TRUNC, 0600));
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024*1024);
+ *
+ * parcFileOutputStream_Write(stream, buffer);
+ *
+ * assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy");
+ *
+ * parcBuffer_Release(&buffer);
+ *
+ * parcFileOutputStream_Release(&stream);
+ * }
+ * @endcode
+ *
+ */
+bool parcFileInputStream_Read(PARCFileInputStream *inputStream, PARCBuffer *buffer);
+
+/**
+ * Read the content of a `PARCFileInputStream` into a {@link PARCBuffer}.
+ *
+ * @param [in] inputStream The `PARCFileInputStream` to read.
+ *
+ * @return non-NULL A pointer to a `PARCBuffer` instance containing the content of the `PARCFileInputStream`.
+ * @return NULl Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCBuffer *parcFileInputStream_ReadFile(PARCFileInputStream *inputStream);
+#endif // libparc_parc_FileInputStream_h
diff --git a/libparc/parc/algol/parc_FileOutputStream.c b/libparc/parc/algol/parc_FileOutputStream.c
new file mode 100755
index 00000000..a17dc66c
--- /dev/null
+++ b/libparc/parc/algol/parc_FileOutputStream.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/algol/parc_Object.h>
+
+PARCOutputStreamInterface *PARCFileOutputStreamAsPARCInputStream = &(PARCOutputStreamInterface) {
+ .Acquire = (PARCOutputStream * (*)(PARCOutputStream *))parcFileOutputStream_Acquire,
+ .Release = (void (*)(PARCOutputStream **))parcFileOutputStream_Release,
+ .Write = (size_t (*)(PARCOutputStream *, PARCBuffer *))parcFileOutputStream_Write
+};
+
+struct parc_file_output_stream {
+ int fd;
+};
+
+static void
+_destroy(PARCFileOutputStream **streamPtr)
+{
+ PARCFileOutputStream *stream = *streamPtr;
+
+ close(stream->fd);
+}
+
+parcObject_ExtendPARCObject(PARCFileOutputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCFileOutputStream *
+parcFileOutputStream_Create(int fileDescriptor)
+{
+ assertTrue(fileDescriptor != -1, "Invalid file descriptor");
+
+ PARCFileOutputStream *result = parcObject_CreateInstance(PARCFileOutputStream);
+ result->fd = fileDescriptor;
+
+ return result;
+}
+
+PARCOutputStream *
+parcFileOutputStream_AsOutputStream(PARCFileOutputStream *fileOutputStream)
+{
+ return parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream), PARCFileOutputStreamAsPARCInputStream);
+}
+
+parcObject_ImplementAcquire(parcFileOutputStream, PARCFileOutputStream);
+
+parcObject_ImplementRelease(parcFileOutputStream, PARCFileOutputStream);
+
+bool
+parcFileOutputStream_Write(PARCFileOutputStream *outputStream, PARCBuffer *buffer)
+{
+ const size_t maximumChunkSize = 1024 * 1024;
+
+ while (parcBuffer_HasRemaining(buffer)) {
+ size_t remaining = parcBuffer_Remaining(buffer);
+ size_t chunkSize = remaining > maximumChunkSize ? maximumChunkSize : remaining;
+ void *buf = parcBuffer_Overlay(buffer, chunkSize);
+ ssize_t nwritten = write(outputStream->fd, buf, chunkSize);
+ if (nwritten == -1) {
+ break;
+ }
+ }
+
+ return parcBuffer_HasRemaining(buffer) == false;
+}
diff --git a/libparc/parc/algol/parc_FileOutputStream.h b/libparc/parc/algol/parc_FileOutputStream.h
new file mode 100644
index 00000000..51251561
--- /dev/null
+++ b/libparc/parc/algol/parc_FileOutputStream.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_FileOutputStream.h
+ * @ingroup inputoutput
+ * @brief A file output stream is an output stream for writing data to a File or to a FileDescriptor.
+ *
+ * Whether or not a file is available or may be created depends upon the underlying platform.
+ * Some platforms, in particular, allow a file to be opened for writing by only one FileOutputStream
+ * (or other file-writing object) at a time. In such situations the constructors in this class will
+ * fail if the file involved is already open.
+ *
+ */
+
+#ifndef libparc_parc_FileOutputStream_h
+#define libparc_parc_FileOutputStream_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_OutputStream.h>
+
+struct parc_file_output_stream;
+typedef struct parc_file_output_stream PARCFileOutputStream;
+
+/**
+ * The mapping of a `PARCFileOutputStream` to the generic `PARCInputStream`.
+ *
+ */
+extern PARCOutputStreamInterface *PARCFileOutputStreamAsPARCOutputStream;
+
+/**
+ * Create a new output stream on a file descriptor.
+ *
+ * Caution: When the resulting `PARCFileOutputStream` is released, the file descriptor is closed.
+ * If you wrap STDOUT_FILENO, for example, the standard output of the application will be closed
+ * when this PARCFileOutputStream is released.
+ * To avoid this, use dup(2) or dup2(2).
+ *
+ * @param [in] fileDescriptor The fileDescriptor for the file on which to create an output stream.
+ *
+ * @return A pointer to a new instance of `PARCFileOutputStream`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileOutputStream *parcFileOutputStream_Create(int fileDescriptor);
+
+/**
+ * Convert an instance of `PARCFileOutputStream` to a `PARCOutputStream`.
+ *
+ * @param [in] fileOutputStream A pointer to a valid PARCFileOutputStream.
+ *
+ * @return A pointer to a new instance of `PARCOutputStream`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCOutputStream *parcFileOutputStream_AsOutputStream(PARCFileOutputStream *fileOutputStream);
+
+/**
+ * Acquire a new reference to an instance of `PARCFileOutputStream`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] stream The instance of `PARCFileOutputStream` to which to refer.
+ *
+ * @return The same value as the input parameter @p stream
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileOutputStream *parcFileOutputStream_Acquire(const PARCFileOutputStream *stream);
+
+/**
+ * Release a `PARCFileOutputStream` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCFileOutputStream`.
+ *
+ * @param [in,out] streamPtr is a pointer to the `PARCFileOutputStream` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcFileOutputStream_Release(PARCFileOutputStream **streamPtr);
+
+/**
+ * Write the contents of a {@link PARCBuffer} to the given `PARCFileOutputStream`.
+ *
+ * The contents of the `PARCBuffer` from the current position to the limit are written to the `PARCFileOutputStream`.
+ * When this function returns the position is set to the end of the last successfully written byte of data.
+ *
+ * @param [in,out] outputStream The `PARCOutputStream` to write to.
+ * @param [in] buffer The `PARCBuffer` to write, from the current position of the buffer to its limit.
+ *
+ * @return true The entire contents of the `PARCBuffer` were written.
+ * @return false The entire contents of the `PARCBuffer` were not written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *stream =
+ * parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT|O_WRONLY|O_TRUNC, 0600));
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024*1024);
+ *
+ * parcFileOutputStream_Write(stream, buffer);
+ *
+ * assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy");
+ *
+ * parcBuffer_Release(&buffer);
+ *
+ * parcFileOutputStream_Release(&stream);
+ * }
+ * @endcode
+ */
+bool parcFileOutputStream_Write(PARCFileOutputStream *outputStream, PARCBuffer *buffer);
+#endif // libparc_parc_FileOutputStream_h
diff --git a/libparc/parc/algol/parc_Hash.c b/libparc/parc/algol/parc_Hash.c
new file mode 100755
index 00000000..1884c74c
--- /dev/null
+++ b/libparc/parc/algol/parc_Hash.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This hash is based on FNV-1a, using different lengths. Please see the FNV-1a
+ * website for details on the algorithm: http://www.isthe.com/chongo/tech/comp/fnv
+ *
+ */
+#include <config.h>
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_hash_32bits {
+ uint32_t accumulator;
+};
+
+parcObject_ExtendPARCObject(PARCHash32Bits, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCHash32Bits *
+parcHash32Bits_Create(void)
+{
+ PARCHash32Bits *result = parcObject_CreateInstance(PARCHash32Bits);
+ if (result != NULL) {
+ result->accumulator = 0;
+ }
+
+ return result;
+}
+
+PARCHash32Bits *
+parcHash32Bits_Update(PARCHash32Bits *hash, const void *data, size_t length)
+{
+ hash->accumulator = parcHash32_Data_Cumulative(data, length, hash->accumulator);
+ return hash;
+}
+
+PARCHash32Bits *
+parcHash32Bits_UpdateUint32(PARCHash32Bits *hash, uint32_t value)
+{
+ hash->accumulator = parcHash32_Data_Cumulative(&value, sizeof(value), hash->accumulator);
+ return hash;
+}
+
+uint32_t
+parcHash32Bits_Hash(PARCHash32Bits *hash)
+{
+ return hash->accumulator;
+}
+
+parcObject_ImplementAcquire(parcHash32Bits, PARCHash32Bits);
+
+parcObject_ImplementRelease(parcHash32Bits, PARCHash32Bits);
+
+/*
+ * Based on 64-bit FNV-1a
+ */
+uint64_t
+parcHash64_Data(const void *data, size_t len)
+{
+ // Standard FNV 64-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint64_t fnv1a_offset = 0xCBF29CE484222325ULL;
+ return parcHash64_Data_Cumulative(data, len, fnv1a_offset);
+}
+
+uint64_t
+parcHash64_Data_Cumulative(const void *data, size_t len, uint64_t lastValue)
+{
+ // Standard FNV 64-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint64_t fnv1a_prime = 0x00000100000001B3ULL;
+ uint64_t hash = lastValue;
+ const char *chardata = data;
+
+ for (size_t i = 0; i < len; i++) {
+ hash = hash ^ chardata[i];
+ hash = hash * fnv1a_prime;
+ }
+
+ return hash;
+}
+
+uint64_t
+parcHash64_Int64(uint64_t int64)
+{
+ return parcHash64_Data(&int64, sizeof(uint64_t));
+}
+
+uint64_t
+parcHash64_Int32(uint32_t int32)
+{
+ return parcHash64_Data(&int32, sizeof(uint32_t));
+}
+
+uint32_t
+parcHash32_Data(const void *data, size_t len)
+{
+ // Standard FNV 32-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint32_t fnv1a_offset = 0x811C9DC5;
+ return parcHash32_Data_Cumulative(data, len, fnv1a_offset);
+}
+
+uint32_t
+parcHash32_Data_Cumulative(const void *data, size_t len, uint32_t lastValue)
+{
+ // Standard FNV 32-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint32_t fnv1a_prime = 0x01000193;
+ uint32_t hash = lastValue;
+
+ const char *chardata = data;
+
+ for (size_t i = 0; i < len; i++) {
+ hash = hash ^ chardata[i];
+ hash = hash * fnv1a_prime;
+ }
+
+ return hash;
+}
+
+uint32_t
+parcHash32_Int64(uint64_t int64)
+{
+ return parcHash32_Data(&int64, sizeof(uint64_t));
+}
+
+uint32_t
+parcHash32_Int32(uint32_t int32)
+{
+ return parcHash32_Data(&int32, sizeof(uint32_t));
+}
diff --git a/libparc/parc/algol/parc_Hash.h b/libparc/parc/algol/parc_Hash.h
new file mode 100755
index 00000000..92227041
--- /dev/null
+++ b/libparc/parc/algol/parc_Hash.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Hash.h
+ * @ingroup datastructures
+ * @brief Implements the FNV-1a 64-bit and 32-bit hashes.
+ *
+ * These are some basic hashing functions for blocks of data and integers. They
+ * generate 64 and 32 bit hashes (They are currently using the FNV-1a algorithm.)
+ * There is also a cumulative version of the hashes that can be used if intermediary
+ * hashes are required/useful.
+ *
+ */
+#ifndef libparc_parc_Hash_h
+#define libparc_parc_Hash_h
+
+#include <stdint.h>
+#include <stdlib.h>
+
+
+struct parc_hash_32bits;
+/**
+ * @typedef PARCHash32Bits
+ * @brief An accumulator
+ */
+
+typedef struct parc_hash_32bits PARCHash32Bits;
+
+/**
+ * Create a 32 bit hash generator
+ *
+ * @return A pointer to a `PARCHash32Bits` instance
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_Create(void);
+
+/**
+ * Generate a 32 bit hash from a memory block starting with a previous hash
+ *
+ * This is a typed version of {@link parcHash32_Data_Cumulative}
+ *
+ * @param [in] hash the value of the last cumulative hash calculated
+ * @param [in] data pointer to a memory block.
+ * @param [in] length length of the memory pointed to by data
+ *
+ * @return pointer to a {@link PARCHash32Bits} with the cumulative hash
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_Update(PARCHash32Bits *hash, const void *data, size_t length);
+
+/**
+ * Generate a 32 bit hash from a uint32 starting with a previous hash
+ * Update the cumulative state of the given {@link PARCHash32Bits}
+ *
+ * @param [in] hash the value of the last cumulative hash calculated
+ * @param [in] value The `uint32` to be hashed
+ *
+ * @return pointer to a `PARCHash32Bits` with the cumulative hash
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_UpdateUint32(PARCHash32Bits *hash, uint32_t value);
+
+/**
+ * Get the current value of the cummulative state of the given {@link PARCHash32Bits}.
+ *
+ * @param [in] hash the value of the last cumulative hash calculated
+ *
+ * @return The hash value as an unsigned 32 bit integer
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint32_t parcHash32Bits_Hash(PARCHash32Bits *hash);
+
+/**
+ * Acquire a new reference to the given {@link PARCHash32Bits} instance.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] hash The instance of `PARCHash32Bits` to which to refer.
+ *
+ * @return The same value as the input parameter @p hash
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_Acquire(const PARCHash32Bits *hash);
+
+/**
+ * Release a reference to the given {@link PARCHash32Bits} instance.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCHash32Bits`.
+ *
+ * @param [in,out] hash is a pointer to the `PARCHash32Bits` reference.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcHash32Bits_Release(PARCHash32Bits **hash);
+
+/**
+ * Generate a 64 bit hash from a memory block
+ *
+ * This function will generate a 64bit hash from a block of memory. The memory block
+ * is not modified in any way.
+ *
+ * The output of this function can be used as input for the cumulative version of
+ * this function
+ *
+ * @param [in] data A pointer to a memory block.
+ * @param [in] len The length of the memory pointed to by data
+ *
+ * @return hash_64bit A 64 bit hash of the memory block.
+ *
+ * Example:
+ * @code
+ *
+ * char * data = "Hello world of hashing";
+ * uint64_t myhash = parcHash64_Data(data,strlen(data));
+ *
+ * @endcode
+ *
+ * @see {@link parcHash64_Data_Cumulative}
+ */
+uint64_t parcHash64_Data(const void *data, size_t len);
+
+/**
+ * Generate a 64 bit hash from a memory block starting with a previous hash
+ *
+ * This function will generate a 64 bit hash from a block of memory and an initial
+ * hash. This is used to cumulatively calculate a hash of larger block. So,
+ * one could generate the hash of the first part of the data (A), then calculate the
+ * hash including the next part of the data (AB) and then the hash of the next
+ * part (ABC). This is useful for not having to recalculate the hash of the parts
+ * you have already hashed.
+ *
+ * A cumulative hash should have the same value as a full hash of the complete data.
+ * So cumulative_hash(B,len(B),hash(A)) is equal to hash(AB,len(AB)).
+ *
+ * @param [in] data pointer to a memory block.
+ * @param [in] len length of the memory pointed to by data
+ * @param [in] lastValue the vale of the last cumulative hash calculated
+ *
+ * @return cumulative_hash64 A 64 bit hash of the data _and_ the data that was
+ * hashed before (represented by lastValue).
+ *
+ * Example:
+ * @code
+ *
+ * char * data1 = "1234567890";
+ * uint64_t myhash1 = parcHash64_Data(data1,10);
+ * char * data2 = "abcdefghij";
+ * uint64_t myhash2 = parcHash64_Data_Cumulative(data2,10,myhash1);
+ * char * data3 = "1234567890abcdefghij";
+ * uint64_t myhash3 = parcHash64_Data(data3,20);
+ * // myhash3 will be equal to myhash2
+ *
+ * @endcode
+ *
+ * @see {@link parcHash64_Data}
+ */
+uint64_t parcHash64_Data_Cumulative(const void *data, size_t len, uint64_t lastValue);
+
+/**
+ * Generate a 64 bit hash from a 64 bit Integer
+ *
+ * This function hashes a 64 bit integer into a 64 bit hash
+ *
+ * @param [in] int64 A 64 bit integer
+ *
+ * @return hash64 A 64 bit hash of the 64 bit integer
+ *
+ * Example:
+ * @code
+ * uint64_t id64 = 1234567890123456;
+ * uint64_t hash64 = parcHash64_Int64(id64);
+ * @endcode
+ *
+ */
+uint64_t parcHash64_Int64(uint64_t int64);
+
+/**
+ * Generate a 64 bit hash from a 32 bit Integer
+ *
+ * This function hashes a 32 bit integer into a 64 bit hash
+ *
+ * @param [in] int32 A 32 bit integer
+ *
+ * @return hash64 A 64 bit hash of the 32 bit integer
+ *
+ * Example:
+ * @code
+ * uint32_t id32 = 70;
+ * uint64_t hash64 = parcHash64_Int32(id32);
+ * @endcode
+ *
+ */
+uint64_t parcHash64_Int32(uint32_t int32);
+
+/**
+ * Generate a 32 bit hash from a memory block
+ *
+ * This function will generate a 32bit hash from a block of memory. The memory block
+ * is not modified in any way.
+ * The output of this function can be used as input for the cumulative version of
+ * this function.
+ *
+ * @param [in] data pointer to a memory block.
+ * @param [in] len length of the memory pointed to by data
+ *
+ * @return hash_32bit A 32 bit hash of the memory block.
+ *
+ * Example:
+ * @code
+ *
+ * char * data = "Hello world of hashing";
+ * uint32_t myhash = parcHash32_Data(data,strlen(data));
+ *
+ * @endcode
+ *
+ * @see {@link parcHash32_Data_Cumulative}
+ */
+uint32_t parcHash32_Data(const void *data, size_t len);
+
+/**
+ * Generate a 32 bit hash from a memory block starting with a previous hash
+ *
+ * This function will generate a 32 bit hash from a block of memory and an initial
+ * hash. This is used to cumulatively calculate a hash of larger block. So,
+ * one could generate the hash of the first part of the data (A), then calculate the
+ * hash including the next part of the data (AB) and then the hash of the next
+ * part (ABC). This is useful for not having to recalculate the hash of the parts
+ * you have already hashed.
+ *
+ * A cumulative hash should have the same value as a full hash of the complete data.
+ * So cumulative_hash(B,len(B),hash(A)) is equal to hash(AB,len(AB)).
+ *
+ * @param [in] data pointer to a memory block.
+ * @param [in] len length of the memory pointed to by data
+ * @param [in] lastValue the vale of the last cumulative hash calculated
+ *
+ * @return cumulative_hash32 A 32 bit hash of the data _and_ the data that was
+ * hashed before (represented by lastValue).
+ *
+ * Example:
+ * @code
+ *
+ * char * data1 = "1234567890";
+ * uint32_t myhash1 = parcHash32_Data(data1,10);
+ * char * data2 = "abcdefghij";
+ * uint32_t myhash2 = parcHash32_Data_Cumulative(data2,10,myhash1);
+ * char * data3 = "1234567890abcdefghij";
+ * uint32_t myhash3 = parcHash32_Data(data3,20);
+ * // myhash3 will be equal to myhash2
+ *
+ * @endcode
+ *
+ * @see {@link parcHash32_Data}
+ */
+uint32_t parcHash32_Data_Cumulative(const void *data, size_t len, uint32_t lastValue);
+
+/**
+ * Generate a 32 bit hash from a 64 bit Integer
+ *
+ * This function hashes a 64 bit integer into a 32 bit hash
+ *
+ * @param [in] int64 A 64 bit integer
+ *
+ * @return hash32 A 32 bit hash of the 64 bit integer
+ *
+ * Example:
+ * @code
+ * uint64_t id64 = 1234567890123456;
+ * uint32_t hash32 = parcHash32_Int64(id64);
+ * @endcode
+ *
+ */
+uint32_t parcHash32_Int64(uint64_t int64);
+
+/**
+ * Generate a 32 bit hash from a 32 bit Integer
+ *
+ * This function hashes a 32 bit integer into a 32 bit hash
+ *
+ * @param [in] int32 A 32 bit integer
+ *
+ * @return hash32 A 32 bit hash of the 32 bit integer
+ *
+ * Example:
+ * @code
+ * uint32_t id32 = 1234567890123456;
+ * uint32_t hash32 = parcHash32_Int32(id32);
+ * @endcode
+ *
+ */
+uint32_t parcHash32_Int32(uint32_t int32);
+#endif // libparc_parc_Hash_h
diff --git a/libparc/parc/algol/parc_HashCode.c b/libparc/parc/algol/parc_HashCode.c
new file mode 100755
index 00000000..8554429c
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCode.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_HashCode.h>
+
+#if PARCHashCodeSize == 64
+static const PARCHashCode _fnv1a_prime = 0x00000100000001B3ULL;
+const PARCHashCode parcHashCode_InitialValue = 0xCBF29CE484222325ULL;
+#else
+static const PARCHashCode _fnv1a_prime = 0x01000193;
+const PARCHashCode parcHashCode_InitialValue = 0x811C9DC5;
+#endif
+
+PARCHashCode
+parcHashCode_HashImpl(const uint8_t *memory, size_t length, PARCHashCode initialValue)
+{
+ // Standard FNV 64-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+
+ PARCHashCode hash = initialValue;
+
+ for (size_t i = 0; i < length; i++) {
+ hash = hash ^ memory[i];
+ hash = hash * _fnv1a_prime;
+ }
+
+ return hash;
+}
+
+PARCHashCode
+parcHashCode_HashHashCode(PARCHashCode initialValue, PARCHashCode update)
+{
+ return parcHashCode_HashImpl((uint8_t *) &update, sizeof(PARCHashCode), initialValue);
+}
diff --git a/libparc/parc/algol/parc_HashCode.h b/libparc/parc/algol/parc_HashCode.h
new file mode 100755
index 00000000..dd572bee
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCode.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_HashCode.h
+ * @ingroup object
+ * @brief The type returned from implementations of the _HashCode() function.
+ *
+ * The size of a PARCHashCode value may be different depending on the compile-time compilation environment.
+ *
+ */
+#ifndef PARC_Library_parc_HashCode_h
+#define PARC_Library_parc_HashCode_h
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#define PARCHashCodeSize 64
+//#define PARCHashCodeSize 32
+
+/**
+ * @typedef PARCHashCode
+ * @brief The type returned from implementations of the _HashCode() function.
+ */
+#if PARCHashCodeSize == 64
+#define PRIPARCHashCode PRIu64
+#define PRIXPARCHashCode PRIX64
+#define PRIxPARCHashCode PRIx64
+typedef uint64_t PARCHashCode;
+
+#else
+#define PRIPARCHashCode PRIu32
+#define PRIXPARCHashCode PRIX32
+#define PRIxPARCHashCode PRIx32
+typedef uint32_t PARCHashCode;
+
+#endif
+
+extern const PARCHashCode parcHashCode_InitialValue;
+
+#define parcHashCode_Hash(_memory_, _length_) parcHashCode_HashImpl(_memory_, _length_, parcHashCode_InitialValue)
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] memory A pointer to bytes used to generate the `PARCHashCode`.
+ * @param [in] length The number of bytes in memory to use to generate the `PARCHashCode`
+ * @param [in] initialValue An inital value for the `PARCHashCode`.
+ *
+ * @return The resulting `PARCHashCode` value.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHashCode parcHashCode_HashImpl(const uint8_t *memory, size_t length, PARCHashCode initialValue);
+
+/**
+ * Hash a PARcHashCode into an existing PARCHashCode.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] initialValue The PARCHashCode initial value
+ * @param [in] update The PARCHashCode value to update the initial value.
+ *
+ * @return The updated PARCHashCode value
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHashCode parcHashCode_HashHashCode(PARCHashCode initialValue, PARCHashCode update);
+#endif
diff --git a/libparc/parc/algol/parc_HashCodeTable.c b/libparc/parc/algol/parc_HashCodeTable.c
new file mode 100755
index 00000000..ea1945b3
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCodeTable.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implements an open-addressing hash table. We use linear probing of +1 per step.
+ *
+ * Table is rehashed when we reach 75% utilization.
+ * The table is rehashed if we go more than 10 linear probes without being able to insert.
+ *
+ * HashCodeTable is a wrapper that holds the key/data management functions. It also
+ * has LinearAddressingHashTable that is the actual hash table.
+ *
+ * This open-addressing table is inefficient for GET or DEL if the element does not exist.
+ * The whole table needs to be
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+
+// minimum size if nothing specified
+#define MIN_SIZE 256
+
+// when we expand, use this factor
+#define EXPAND_FACTOR 2
+
+#define MAX_PROBE_LENGTH 20
+
+typedef enum {
+ ADD_OK, // we added the key
+ ADD_DUP, // the key is a duplicate
+ ADD_NOSPACE // ran out of space
+} PARCHashCodeTable_AddResult;
+
+typedef struct hashtable_entry {
+ // A hashtable entry is in use if the key is non-null
+ void *key;
+ void *data;
+ HashCodeType hashcode;
+} HashTableEntry;
+
+typedef struct linear_address_hash_table {
+ HashTableEntry *entries;
+
+ // Number of elements allocated
+ size_t tableLimit;
+
+ // Number of elements in use
+ size_t tableSize;
+
+ // When the tableSize equals or exceeds this
+ // threshold, we should expand and re-hash the table∫
+ size_t expandThreshold;
+} LinearAddressingHashTable;
+
+struct parc_hashcode_table {
+ LinearAddressingHashTable hashtable;
+
+ PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc;
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc;
+ PARCHashCodeTable_Destroyer keyDestroyer;
+ PARCHashCodeTable_Destroyer dataDestroyer;
+
+ unsigned expandCount;
+};
+
+static bool
+_findIndex(PARCHashCodeTable *table, const void *key, size_t *outputIndexPtr)
+{
+ size_t index, start;
+ HashCodeType hashcode;
+ LinearAddressingHashTable *innerTable;
+
+ innerTable = &table->hashtable;
+ hashcode = table->keyHashCodeFunc(key);
+ index = hashcode % innerTable->tableLimit;
+ start = index;
+
+
+ // check until we've gone MAX_PROBE_LENGTH
+ unsigned steps = 0;
+ do {
+ if (innerTable->entries[index].key != NULL) {
+ if ((innerTable->entries[index].hashcode == hashcode) && table->keyEqualsFunc(key, innerTable->entries[index].key)) {
+ // the key already exists in the table
+ *outputIndexPtr = index;
+ return true;
+ }
+ }
+ steps++;
+ index = index + 1;
+ if (index == innerTable->tableLimit) {
+ index = 0;
+ }
+ } while (index != start && steps < MAX_PROBE_LENGTH);
+
+ return false;
+}
+
+static PARCHashCodeTable_AddResult
+_innerTableAdd(LinearAddressingHashTable *innerTable, PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ HashCodeType hashcode, void *key, void *data)
+{
+ size_t index = hashcode % innerTable->tableLimit;
+
+ unsigned steps = 0;
+
+ // we know the size < limit, so it will fit eventually
+ while (steps < MAX_PROBE_LENGTH) {
+ if (innerTable->entries[index].key == NULL) {
+ innerTable->entries[index].hashcode = hashcode;
+ innerTable->entries[index].key = key;
+ innerTable->entries[index].data = data;
+ innerTable->tableSize++;
+ return ADD_OK;
+ }
+
+ if ((innerTable->entries[index].hashcode == hashcode) && keyEqualsFunc(key, innerTable->entries[index].key)) {
+ // the key already exists in the table
+ return ADD_DUP;
+ }
+
+ steps++;
+ index = index + 1;
+ if (index == innerTable->tableLimit) {
+ index = 0;
+ }
+ }
+
+ return ADD_NOSPACE;
+}
+
+static PARCHashCodeTable_AddResult
+_rehash(LinearAddressingHashTable *old_table, LinearAddressingHashTable *new_table, PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc)
+{
+ size_t i;
+ for (i = 0; i < old_table->tableLimit; i++) {
+ if (old_table->entries[i].key != NULL) {
+ PARCHashCodeTable_AddResult result = _innerTableAdd(new_table, keyEqualsFunc, old_table->entries[i].hashcode,
+ old_table->entries[i].key, old_table->entries[i].data);
+ if (result != ADD_OK) {
+ return result;
+ }
+ }
+ }
+ return ADD_OK;
+}
+
+static void
+_expand(PARCHashCodeTable *hashCodeTable)
+{
+ LinearAddressingHashTable temp_table;
+ LinearAddressingHashTable *old_table = &hashCodeTable->hashtable;
+
+ size_t expandby = EXPAND_FACTOR;
+
+ // start with a copy of the current table
+ PARCHashCodeTable_AddResult result = ADD_OK;
+ do {
+ hashCodeTable->expandCount++;
+
+ temp_table.tableSize = 0;
+ temp_table.tableLimit = old_table->tableLimit * expandby;
+ temp_table.expandThreshold = temp_table.tableLimit - temp_table.tableLimit / 4;
+ temp_table.entries = parcMemory_AllocateAndClear(temp_table.tableLimit * sizeof(HashTableEntry));
+ assertNotNull(temp_table.entries, "parcMemory_AllocateAndClear(%zu) returned NULL", temp_table.tableLimit * sizeof(HashTableEntry));
+
+ result = _rehash(old_table, &temp_table, hashCodeTable->keyEqualsFunc);
+ if (result == ADD_NOSPACE) {
+ // could not rehash, so expand by more and try again
+ parcMemory_Deallocate((void **) &(temp_table.entries));
+ expandby++;
+ }
+ } while (result == ADD_NOSPACE);
+
+ parcMemory_Deallocate((void **) &old_table->entries);
+ hashCodeTable->hashtable = temp_table;
+}
+
+PARCHashCodeTable *
+parcHashCodeTable_Create_Size(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer,
+ size_t minimumSize)
+{
+ PARCHashCodeTable *table = parcMemory_AllocateAndClear(sizeof(PARCHashCodeTable));
+ assertNotNull(table, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCHashCodeTable));
+
+ assertNotNull(keyEqualsFunc, "keyEqualsFunc must be non-null");
+ assertNotNull(keyHashCodeFunc, "keyHashCodeFunc must be non-null");
+ assertTrue(minimumSize > 0, "minimumSize must be greater than zero");
+
+ table->keyEqualsFunc = keyEqualsFunc;
+ table->keyHashCodeFunc = keyHashCodeFunc;
+ table->keyDestroyer = keyDestroyer;
+ table->dataDestroyer = dataDestroyer;
+
+ table->hashtable.entries = parcMemory_AllocateAndClear(minimumSize * sizeof(HashTableEntry));
+ assertNotNull(table->hashtable.entries, "parcMemory_AllocateAndClear(%zu) returned NULL", minimumSize * sizeof(HashTableEntry));
+ table->hashtable.tableLimit = minimumSize;
+ table->hashtable.tableSize = 0;
+
+ memset(table->hashtable.entries, 0, minimumSize * sizeof(HashTableEntry));
+
+ // expand at 75% utilization
+ table->hashtable.expandThreshold = minimumSize - minimumSize / 4;
+
+ return table;
+}
+
+PARCHashCodeTable *
+parcHashCodeTable_Create(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer)
+{
+ return parcHashCodeTable_Create_Size(keyEqualsFunc, keyHashCodeFunc, keyDestroyer, dataDestroyer, MIN_SIZE);
+}
+
+void
+parcHashCodeTable_Destroy(PARCHashCodeTable **tablePtr)
+{
+ assertNotNull(tablePtr, "Parameter must be non-null double pointer");
+ assertNotNull(*tablePtr, "Parameter must dereference to non-null pointer");
+ PARCHashCodeTable *table = *tablePtr;
+ size_t i;
+
+ for (i = 0; i < table->hashtable.tableLimit; i++) {
+ if (table->hashtable.entries[i].key != NULL) {
+ if (table->keyDestroyer) {
+ table->keyDestroyer(&table->hashtable.entries[i].key);
+ }
+
+ if (table->dataDestroyer) {
+ table->dataDestroyer(&table->hashtable.entries[i].data);
+ }
+ }
+ }
+
+ parcMemory_Deallocate((void **) &(table->hashtable.entries));
+ parcMemory_Deallocate((void **) &table);
+ *tablePtr = NULL;
+}
+
+bool
+parcHashCodeTable_Add(PARCHashCodeTable *table, void *key, void *data)
+{
+ assertNotNull(table, "Parameter table must be non-null");
+ assertNotNull(key, "Parameter key must be non-null");
+ assertNotNull(data, "Parameter data must be non-null");
+
+ if (table->hashtable.tableSize >= table->hashtable.expandThreshold) {
+ _expand(table);
+ }
+
+ HashCodeType hashcode = table->keyHashCodeFunc(key);
+
+ PARCHashCodeTable_AddResult result = ADD_OK;
+ do {
+ result = _innerTableAdd(&table->hashtable, table->keyEqualsFunc, hashcode, key, data);
+ if (result == ADD_NOSPACE) {
+ _expand(table);
+ }
+ } while (result == ADD_NOSPACE);
+
+ return (result == ADD_OK);
+}
+
+void
+parcHashCodeTable_Del(PARCHashCodeTable *table, const void *key)
+{
+ size_t index;
+ bool found;
+
+ assertNotNull(table, "Parameter table must be non-null");
+ assertNotNull(key, "parameter key must be non-null");
+
+ found = _findIndex(table, key, &index);
+
+ if (found) {
+ assertTrue(table->hashtable.tableSize > 0, "Illegal state: found entry in a hash table with 0 size");
+
+ if (table->keyDestroyer) {
+ table->keyDestroyer(&table->hashtable.entries[index].key);
+ }
+
+ if (table->dataDestroyer) {
+ table->dataDestroyer(&table->hashtable.entries[index].data);
+ }
+
+ memset(&table->hashtable.entries[index], 0, sizeof(HashTableEntry));
+
+ table->hashtable.tableSize--;
+ }
+}
+
+void *
+parcHashCodeTable_Get(PARCHashCodeTable *table, const void *key)
+{
+ size_t index;
+
+ assertNotNull(table, "Parameter table must be non-null");
+ assertNotNull(key, "parameter key must be non-null");
+
+ bool found = _findIndex(table, key, &index);
+
+ if (found) {
+ return table->hashtable.entries[index].data;
+ }
+
+ return NULL;
+}
+
+size_t
+parcHashCodeTable_Length(const PARCHashCodeTable *table)
+{
+ assertNotNull(table, "Parameter table must be non-null");
+ return table->hashtable.tableSize;
+}
diff --git a/libparc/parc/algol/parc_HashCodeTable.h b/libparc/parc/algol/parc_HashCodeTable.h
new file mode 100644
index 00000000..58b3d016
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCodeTable.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_HashCodeTable.h
+ * @ingroup datastructures
+ *
+ * A hashcode table requires the user to specify their own hash function
+ * to operate on the object type being inserted.
+ *
+ */
+#ifndef libparc_parc_HashCodeTable_h
+#define libparc_parc_HashCodeTable_h
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_HashCode.h>
+
+struct parc_hashcode_table;
+typedef struct parc_hashcode_table PARCHashCodeTable;
+
+typedef PARCHashCode HashCodeType;
+
+
+/**
+ * @typedef PARCHashCodeTable_KeyEqualsFunc
+ * @brief Are two keys equal?
+ *
+ */
+
+typedef bool (*PARCHashCodeTable_KeyEqualsFunc)(const void *keyA, const void *keyB);
+
+/**
+ * @typedef PARCHashCodeTable_HashCodeFunc
+ */
+
+typedef HashCodeType (*PARCHashCodeTable_HashCodeFunc)(const void *keyA);
+
+/**
+ * @typedef PARCHashCodeTable_Destroyer
+ */
+
+typedef void (*PARCHashCodeTable_Destroyer)(void **keyOrDataPtr);
+
+/**
+ * Create a Hash Table based on hash codes.
+ *
+ * @param [in] keyEqualsFunc Tests keys for equality.
+ * @param [in] keyHashCodeFunc Returns the hash code of a key
+ * @param [in] keyDestroyer Called on Remove or Destroy to free stored keys, may be NULL.
+ * @param [in] dataDestroyer Called on Remove or Destroy to free stored data, may be NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCHashCodeTable *parcHashCodeTable_Create(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer);
+
+
+/**
+ * Create a Hash Table based on hash codes.
+ *
+ * @param [in] keyEqualsFunc Tests keys for equality.
+ * @param [in] keyHashCodeFunc Returns the hash code of a key
+ * @param [in] keyDestroyer Called on Remove or Destroy to free stored keys, may be NULL.
+ * @param [in] dataDestroyer Called on Remove or Destroy to free stored data, may be NULL.
+ * @param [in] minimumSize The minimum size of the table
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCHashCodeTable *parcHashCodeTable_Create_Size(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer,
+ size_t minimumSize);
+
+/**
+ * Destroy the table and free all saved objects
+ *
+ * @param [in,out] tablePtr is a pointer to the `PARCHashCodeTable` reference.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcHashCodeTable_Destroy(PARCHashCodeTable **tablePtr);
+
+/**
+ * Add an element to the hash table.
+ * @param [in,out] table The key, must be usable with the {@link PARCHashCodeTable_KeyEqualsFunc} and {@link PARCHashCodeTable_HashCodeFunc}.
+ * @param [in] key The key, must be usable with the `keyEqualsFunc` and `keyHashCodeFunc`.
+ * @param [in] data The value, must not be NULL
+ *
+ * @return true if key did not exist and data was added. Returns false if key exists or error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcHashCodeTable_Add(PARCHashCodeTable *table, void *key, void *data);
+
+/**
+ * Removes a key from an instance of `PARCHashCodeTable`, freeing key and data memory. Does nothing if key does not
+ * exist in the table.
+ *
+ * @param [in,out] table The instance of `PARCHashCodeTable` from which the key will be removed.
+ * @param [in] key The key, must be usable with the {@link PARCHashCodeTable_KeyEqualsFunc} and {@link PARCHashCodeTable_HashCodeFunc}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcHashCodeTable_Del(PARCHashCodeTable *table, const void *key);
+
+/**
+ * Returns the key value, or NULL if the key does not exist
+ *
+ * @param [in] table The instance of `PARCHashCodeTable` from which the the value will be retrieved.
+ * @param [in] key The key to identify the desired value.
+ *
+ * @return A pointer to the value of the specified key.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcHashCodeTable_Get(PARCHashCodeTable *table, const void *key);
+
+/**
+ * Returns the number of entries in the table
+ *
+ *
+ * @param [in] table The specified `PARCHashCodeTable` instance.
+ * @return The number of entries in @p table.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcHashCodeTable_Length(const PARCHashCodeTable *table);
+#endif // libparc_parc_HashCodeTable_h
diff --git a/libparc/parc/algol/parc_HashMap.c b/libparc/parc/algol/parc_HashMap.c
new file mode 100644
index 00000000..35a4414f
--- /dev/null
+++ b/libparc/parc/algol/parc_HashMap.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include "parc_HashMap.h"
+#include "parc_LinkedList.h"
+
+#include <math.h>
+
+static const uint32_t DEFAULT_CAPACITY = 43;
+
+typedef struct PARCHashMapEntry {
+ PARCObject *key;
+ PARCObject *value;
+} _PARCHashMapEntry;
+
+
+static bool
+_parcHashMapEntry_IsValid(_PARCHashMapEntry *hashEntry)
+{
+ bool result = false;
+
+ if (hashEntry) {
+ if (parcObject_IsValid(hashEntry->key)) {
+ if (parcObject_IsValid(hashEntry->value)) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_parcHashMapEntry_Finalize(_PARCHashMapEntry **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCHashMap pointer.");
+ _PARCHashMapEntry *hashMapEntry = *instancePtr;
+
+ _parcHashMapEntry_IsValid(hashMapEntry);
+
+ parcObject_Release(&hashMapEntry->key);
+ parcObject_Release(&hashMapEntry->value);
+}
+
+static bool
+_parcHashMapEntry_Equals(const _PARCHashMapEntry *a, const _PARCHashMapEntry *b)
+{
+ return (parcObject_Equals(a->key, b->key) && parcObject_Equals(a->value, b->value));
+}
+
+
+static PARCHashCode
+_parcHashMapEntry_HashCode(const _PARCHashMapEntry *entry)
+{
+ return parcObject_HashCode(entry->key);
+}
+
+
+struct PARCHashMap {
+ PARCLinkedList **buckets;
+ size_t minCapacity;
+ size_t capacity;
+ size_t size;
+ double maxLoadFactor;
+ double minLoadFactor;
+};
+
+static _PARCHashMapEntry *
+_parcHashMap_GetEntry(const PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCHashCode keyHash = parcObject_HashCode(key);
+
+ int bucket = keyHash % hashMap->capacity;
+
+ _PARCHashMapEntry *result = NULL;
+
+ if (hashMap->buckets[bucket] != NULL) {
+ PARCIterator *iterator = parcLinkedList_CreateIterator(hashMap->buckets[bucket]);
+
+ while (parcIterator_HasNext(iterator)) {
+ _PARCHashMapEntry *entry = parcIterator_Next(iterator);
+ if (parcObject_Equals(key, entry->key)) {
+ result = entry;
+ break;
+ }
+ }
+ parcIterator_Release(&iterator);
+ }
+
+ return result;
+}
+
+//static parcObject_ImplementAcquire(parcHashMapEntry, _PARCHashMapEntry);
+
+static parcObject_ImplementRelease(_parcHashMapEntry, _PARCHashMapEntry);
+
+parcObject_ExtendPARCObject(_PARCHashMapEntry, _parcHashMapEntry_Finalize, NULL, NULL, _parcHashMapEntry_Equals, NULL, _parcHashMapEntry_HashCode, NULL);
+
+static _PARCHashMapEntry *
+_parcHashMapEntry_Create(const PARCObject *key, const PARCObject *value)
+{
+ parcObject_OptionalAssertValid(key);
+ parcObject_OptionalAssertValid(value);
+
+ _PARCHashMapEntry *result = parcObject_CreateInstance(_PARCHashMapEntry);
+
+ result->key = parcObject_Copy(key);
+ result->value = parcObject_Acquire(value);
+
+ return result;
+}
+
+static void
+_parcHashMap_Finalize(PARCHashMap **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCHashMap pointer.");
+ PARCHashMap *hashMap = *instancePtr;
+
+ for (unsigned int i = 0; i < hashMap->capacity; i++) {
+ if (hashMap->buckets[i] != NULL) {
+ parcLinkedList_Release(&hashMap->buckets[i]);
+ }
+ }
+
+ parcMemory_Deallocate(&hashMap->buckets);
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcHashMap, PARCHashMap);
+
+parcObject_ImplementRelease(parcHashMap, PARCHashMap);
+
+parcObject_ExtendPARCObject(PARCHashMap, _parcHashMap_Finalize, parcHashMap_Copy, parcHashMap_ToString, parcHashMap_Equals, NULL, parcHashMap_HashCode, parcHashMap_ToJSON);
+
+void
+parcHashMap_AssertValid(const PARCHashMap *instance)
+{
+ assertTrue(parcHashMap_IsValid(instance),
+ "PARCHashMap is not valid.");
+}
+
+PARCHashMap *
+parcHashMap_CreateCapacity(unsigned int capacity)
+{
+ PARCHashMap *result = parcObject_CreateInstance(PARCHashMap);
+
+ if (result != NULL) {
+ if (capacity == 0) {
+ capacity = DEFAULT_CAPACITY;
+ }
+
+ result->minCapacity = capacity;
+ result->capacity = capacity;
+ result->size = 0;
+ result->maxLoadFactor = 0.75;
+ result->minLoadFactor = result->maxLoadFactor / 3.0;
+ result->buckets = parcMemory_AllocateAndClear(capacity * sizeof(PARCLinkedList*));
+ }
+
+ return result;
+}
+
+PARCHashMap *
+parcHashMap_Create(void)
+{
+ PARCHashMap *result = parcHashMap_CreateCapacity(DEFAULT_CAPACITY);
+
+ return result;
+}
+
+PARCHashMap *
+parcHashMap_Copy(const PARCHashMap *original)
+{
+ parcHashMap_OptionalAssertValid(original);
+
+ PARCHashMap *result = parcObject_CreateInstance(PARCHashMap);
+
+ result->capacity = original->capacity;
+ result->minCapacity = original->minCapacity;
+ result->maxLoadFactor = original->maxLoadFactor;
+ result->minLoadFactor = original->minLoadFactor;
+ result->size = original->size;
+ result->buckets = parcMemory_Allocate(result->capacity * sizeof(PARCLinkedList*));
+
+ for (unsigned int i = 0; i < result->capacity; i++) {
+ result->buckets[i] = NULL;
+ if (original->buckets[i] != NULL) {
+ result->buckets[i] = parcLinkedList_Copy(original->buckets[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+parcHashMap_Display(const PARCHashMap *hashMap, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCHashMap@%p {", hashMap);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator((PARCHashMap *) hashMap);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *keyObject = parcIterator_Next(iterator);
+ const PARCObject *valueObject = parcHashMap_Get(hashMap, keyObject);
+ char *key = parcObject_ToString(keyObject);
+ char *value = parcObject_ToString(valueObject);
+ parcDisplayIndented_PrintLine(indentation + 1, "%s -> %s", key, value);
+ parcMemory_Deallocate(&key);
+ parcMemory_Deallocate(&value);
+ }
+ parcIterator_Release(&iterator);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcHashMap_Equals(const PARCHashMap *x, const PARCHashMap *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ parcHashMap_OptionalAssertValid(x);
+ parcHashMap_OptionalAssertValid(y);
+
+ if (x->capacity == y->capacity) {
+ if (x->size == y->size) {
+ result = true;
+ for (unsigned int i = 0; (i < x->capacity) && result; i++) {
+ if ((x->buckets[i] == NULL) || (y->buckets[i] == NULL)) {
+ result = (x->buckets[i] == y->buckets[i]);
+ } else {
+ // For each item in an X bucket, it must be in the Y bucket.
+ result = parcLinkedList_SetEquals(x->buckets[i], y->buckets[i]);
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcHashMap_HashCode(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+
+ PARCHashCode result = 0;
+
+ for (unsigned int i = 0; i < hashMap->capacity; i++) {
+ if (hashMap->buckets[i] != NULL) {
+ result += parcLinkedList_HashCode(hashMap->buckets[i]);
+ }
+ }
+
+ return result;
+}
+
+bool
+parcHashMap_IsValid(const PARCHashMap *map)
+{
+ bool result = false;
+
+ if (map != NULL) {
+ if (parcObject_IsValid(map)) {
+ result = true;
+
+ for (unsigned int i = 0; i < map->capacity; i++) {
+ if (map->buckets[i] != NULL) {
+ if (parcLinkedList_IsValid(map->buckets[i]) == false) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcHashMap_ToJSON(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+
+ PARCJSON *result = parcJSON_Create();
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator((PARCHashMap *) hashMap);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *keyObject = parcIterator_Next(iterator);
+ const PARCObject *valueObject = parcHashMap_Get(hashMap, keyObject);
+ char *key = parcObject_ToString(keyObject);
+ PARCJSON *value = parcObject_ToJSON(valueObject);
+
+ parcJSON_AddObject(result, key, value);
+
+ parcMemory_Deallocate(&key);
+ parcJSON_Release(&value);
+ }
+
+ parcIterator_Release(&iterator);
+
+
+ return result;
+}
+
+PARCBufferComposer *
+parcHashMap_BuildString(const PARCHashMap *hashMap, PARCBufferComposer *composer)
+{
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator((PARCHashMap *) hashMap);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *keyObject = parcIterator_Next(iterator);
+ const PARCObject *valueObject = parcHashMap_Get(hashMap, keyObject);
+ char *key = parcObject_ToString(keyObject);
+ char *value = parcObject_ToString(valueObject);
+ parcBufferComposer_Format(composer, "%s -> %s\n", key, value);
+ parcMemory_Deallocate(&key);
+ parcMemory_Deallocate(&value);
+ }
+
+ parcIterator_Release(&iterator);
+
+ return composer;
+}
+
+char *
+parcHashMap_ToString(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ parcHashMap_BuildString(hashMap, composer);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+bool
+parcHashMap_Contains(PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ _PARCHashMapEntry *entry = _parcHashMap_GetEntry(hashMap, key);
+ if (entry != NULL) {
+ result = entry->value;
+ }
+
+ return result;
+}
+
+static void
+_parcHashMap_Resize(PARCHashMap *hashMap, size_t newCapacity)
+{
+ if (newCapacity < hashMap->minCapacity) {
+ return;
+ }
+
+ PARCLinkedList **newBuckets = parcMemory_AllocateAndClear(newCapacity * sizeof(PARCLinkedList*));
+
+ for (unsigned int i = 0; i < hashMap->capacity; i++) {
+ if (hashMap->buckets[i] != NULL) {
+ if (!parcLinkedList_IsEmpty(hashMap->buckets[i])) {
+ PARCIterator *elementIt = parcLinkedList_CreateIterator(hashMap->buckets[i]);
+ while (parcIterator_HasNext(elementIt)) {
+ _PARCHashMapEntry *entry = parcIterator_Next(elementIt);
+ PARCHashCode keyHash = parcObject_HashCode(entry->key);
+ int newBucket = keyHash % newCapacity;
+ if (newBuckets[newBucket] == NULL) {
+ newBuckets[newBucket] = parcLinkedList_Create();
+ }
+ parcLinkedList_Append(newBuckets[newBucket], entry);
+ }
+ parcIterator_Release(&elementIt);
+ }
+ parcLinkedList_Release(&hashMap->buckets[i]);
+ }
+ }
+ PARCLinkedList **cleanupBuckets = hashMap->buckets;
+ hashMap->buckets = newBuckets;
+ hashMap->capacity = newCapacity;
+
+ parcMemory_Deallocate(&cleanupBuckets);
+}
+
+bool
+parcHashMap_Remove(PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCHashCode keyHash = parcObject_HashCode(key);
+
+ int bucket = keyHash % hashMap->capacity;
+
+ bool result = false;
+
+ if (hashMap->buckets[bucket] != NULL) {
+ PARCIterator *iterator = parcLinkedList_CreateIterator(hashMap->buckets[bucket]);
+
+ while (parcIterator_HasNext(iterator)) {
+ _PARCHashMapEntry *entry = parcIterator_Next(iterator);
+ if (parcObject_Equals(key, entry->key)) {
+ parcIterator_Remove(iterator);
+ hashMap->size--;
+ result = true;
+ break;
+ }
+ }
+ parcIterator_Release(&iterator);
+ }
+
+ // When expanded by 2 the load factor goes from .75 (3/4) to .375 (3/8), if
+ // we compress by 2 when the load factor is .25 (1/4) the load
+ // factor becomes .5 (1/2).
+ double loadFactor = (double) hashMap->size / (double) hashMap->capacity;
+ if (loadFactor <= (hashMap->minLoadFactor)) {
+ _parcHashMap_Resize(hashMap, hashMap->capacity / 2);
+ }
+
+ return result;
+}
+
+#include <stdio.h>
+
+PARCHashMap *
+parcHashMap_Put(PARCHashMap *hashMap, const PARCObject *key, const PARCObject *value)
+{
+ // When expanded by 2 the load factor goes from .75 (3/4) to .375 (3/8), if
+ // we compress by 2 when the load factor is .25 (1/4) the load
+ // factor becomes .5 (1/2).
+ double loadFactor = (double) hashMap->size / (double) hashMap->capacity;
+ if (loadFactor >= hashMap->maxLoadFactor) {
+ _parcHashMap_Resize(hashMap, hashMap->capacity * 2);
+ }
+
+ _PARCHashMapEntry *entry = _parcHashMap_GetEntry(hashMap, key);
+
+ if (entry != NULL) {
+ if (entry->value != value) {
+ parcObject_Release(&entry->value);
+ entry->value = parcObject_Acquire(value);
+ }
+ } else {
+ entry = _parcHashMapEntry_Create(key, value);
+
+ PARCHashCode keyHash = parcObject_HashCode(key);
+ int bucket = keyHash % hashMap->capacity;
+
+ if (hashMap->buckets[bucket] == NULL) {
+ hashMap->buckets[bucket] = parcLinkedList_Create();
+ }
+ parcLinkedList_Append(hashMap->buckets[bucket], entry);
+ hashMap->size++;
+ _parcHashMapEntry_Release(&entry);
+ }
+
+ return hashMap;
+}
+
+const PARCObject *
+parcHashMap_Get(const PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ _PARCHashMapEntry *entry = _parcHashMap_GetEntry(hashMap, key);
+ if (entry != NULL) {
+ result = entry->value;
+ }
+
+ return result;
+}
+
+size_t
+parcHashMap_Size(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+ return hashMap->size;
+}
+
+double
+parcHashMap_GetClusteringNumber(const PARCHashMap *hashMap)
+{
+ // This function compute the standard deviation of the chain-lengths
+ // from a value of 1.0 (as opposed to the mean) and weights the
+ // result by in inverse of the current load factor. The deviation
+ // from 1.0 is used because the hashmap's max load factor is < 1.0 and
+ // thus the ideal average chain-length is 1.0
+ //
+ // A result of 0.0 equates to an ideal distribution, a result of ~1.0 should
+ // represent a fairly normal or random distribution, and a result > 1.5 or so
+ // implies some amount of undesirable clumping may be happening.
+
+ size_t totalLength = 0;
+ double variance = 0;
+
+ // Compute the variance vs 1.0
+ for (size_t i = 0; i < hashMap->capacity; ++i) {
+ if (hashMap->buckets[i] != NULL) {
+ size_t bucketSize = parcLinkedList_Size(hashMap->buckets[i]);
+ totalLength += bucketSize;
+ variance += (bucketSize - 1) * (bucketSize - 1); //Variance relative to 1
+ }
+ }
+ variance /= ((double) totalLength);
+
+ // Compute the standard deviation
+ double standardDeviation = sqrt(variance);
+
+ // Weight the standard deviation by the inverse of the current load factor
+ return standardDeviation * ((double) hashMap->capacity / (double) totalLength);
+}
+
+typedef struct {
+ PARCHashMap *map;
+ int bucket;
+ PARCIterator *listIterator;
+ _PARCHashMapEntry *current;
+} _PARCHashMapIterator;
+
+static _PARCHashMapIterator *
+_parcHashMap_Init(PARCHashMap *map __attribute__((unused)))
+{
+ _PARCHashMapIterator *state = parcMemory_AllocateAndClear(sizeof(_PARCHashMapIterator));
+
+ if (state != NULL) {
+ state->map = map;
+ state->bucket = 0;
+ state->listIterator = NULL;
+ for (size_t i = 0; i < map->capacity; ++i) {
+ if (map->buckets[i] != NULL) {
+ state->bucket = i;
+ state->listIterator = parcLinkedList_CreateIterator(map->buckets[i]);
+ break;
+ }
+ }
+
+ trapOutOfMemoryIf(state->listIterator == NULL, "Cannot create parcLinkedList_CreateIterator");
+ }
+
+ return state;
+}
+
+static bool
+_parcHashMap_Fini(PARCHashMap *map __attribute__((unused)), _PARCHashMapIterator *state __attribute__((unused)))
+{
+ if (state->listIterator != NULL) {
+ parcIterator_Release(&state->listIterator);
+ }
+ parcMemory_Deallocate(&state);
+ return true;
+}
+
+static _PARCHashMapIterator *
+_parcHashMap_Next(PARCHashMap *map __attribute__((unused)), _PARCHashMapIterator *state)
+{
+ _PARCHashMapEntry *result = parcIterator_Next(state->listIterator);
+ state->current = result;
+ return state;
+}
+
+static void
+_parcHashMap_Remove(PARCHashMap *map, _PARCHashMapIterator **statePtr __attribute__((unused)))
+{
+ _PARCHashMapIterator *state = *statePtr;
+
+ if (state->listIterator != NULL) {
+ parcIterator_Remove(state->listIterator);
+ map->size--;
+ }
+}
+
+static bool
+_parcHashMap_HasNext(PARCHashMap *map __attribute__((unused)), _PARCHashMapIterator *state)
+{
+ bool result = false;
+ if (state->listIterator != NULL) {
+ if (parcIterator_HasNext(state->listIterator)) {
+ result = true;
+ } else {
+ while ((result == false) && (++state->bucket < map->capacity)) {
+ if (map->buckets[state->bucket] != NULL) {
+ parcIterator_Release(&state->listIterator);
+ state->listIterator = parcLinkedList_CreateIterator(map->buckets[state->bucket]);
+ trapOutOfMemoryIf(state->listIterator == NULL, "Cannot create parcLinkedList_CreateIterator");
+ result = parcIterator_HasNext(state->listIterator);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static PARCObject *
+_parcHashMapValue_Element(PARCHashMap *map __attribute__((unused)), const _PARCHashMapIterator *state)
+{
+ return state->current->value;
+}
+
+static PARCObject *
+_parcHashMapKey_Element(PARCHashMap *map __attribute__((unused)), const _PARCHashMapIterator *state)
+{
+ return state->current->key;
+}
+
+PARCIterator *
+parcHashMap_CreateValueIterator(PARCHashMap *hashMap)
+{
+ PARCIterator *iterator = parcIterator_Create(hashMap,
+ (void *(*)(PARCObject *))_parcHashMap_Init,
+ (bool (*)(PARCObject *, void *))_parcHashMap_HasNext,
+ (void *(*)(PARCObject *, void *))_parcHashMap_Next,
+ (void (*)(PARCObject *, void **))_parcHashMap_Remove,
+ (void *(*)(PARCObject *, void *))_parcHashMapValue_Element,
+ (void (*)(PARCObject *, void *))_parcHashMap_Fini,
+ NULL);
+
+ return iterator;
+}
+
+
+PARCIterator *
+parcHashMap_CreateKeyIterator(PARCHashMap *hashMap)
+{
+ PARCIterator *iterator = parcIterator_Create(hashMap,
+ (void *(*)(PARCObject *))_parcHashMap_Init,
+ (bool (*)(PARCObject *, void *))_parcHashMap_HasNext,
+ (void *(*)(PARCObject *, void *))_parcHashMap_Next,
+ (void (*)(PARCObject *, void **))_parcHashMap_Remove,
+ (void *(*)(PARCObject *, void *))_parcHashMapKey_Element,
+ (void (*)(PARCObject *, void *))_parcHashMap_Fini,
+ NULL);
+
+ return iterator;
+}
diff --git a/libparc/parc/algol/parc_HashMap.h b/libparc/parc/algol/parc_HashMap.h
new file mode 100755
index 00000000..3ab26cd9
--- /dev/null
+++ b/libparc/parc/algol/parc_HashMap.h
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_HashMap.h
+ * @ingroup datastructures
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_HashMap
+#define PARCLibrary_parc_HashMap
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct PARCHashMap;
+typedef struct PARCHashMap PARCHashMap;
+
+/**
+ * Increase the number of references to a `PARCHashMap` instance.
+ *
+ * Note that new `PARCHashMap` is not created,
+ * only that the given `PARCHashMap` reference count is incremented.
+ * Discard the reference by invoking `parcHashMap_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * PARCHashMap *b = parcHashMap_Acquire();
+ *
+ * parcHashMap_Release(&a);
+ * parcHashMap_Release(&b);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Acquire(const PARCHashMap *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcHashMap_OptionalAssertValid(_instance_)
+#else
+# define parcHashMap_OptionalAssertValid(_instance_) parcHashMap_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCHashMap` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcHashMap_Release(&b);
+ * }
+ * @endcode
+ */
+void parcHashMap_AssertValid(const PARCHashMap *instance);
+
+/**
+ * Constructs an empty `PARCHashMap` with a default minimum number of 'buckets'.
+ *
+ * The capacity will expand and contract as needed to keep load factor table
+ * below the max load factor of 0.75 and above the minimum load factor or 0.25.
+ * The default minimum number of buckets is 42.
+ *
+ * @return non-NULL A pointer to a valid PARCHashMap instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Create(void);
+
+/**
+ * Constructs an empty `PARCHashMap` with the specified minimum number of 'buckets'.
+ *
+ * The capacity will expand and contract as needed to keep load factor table
+ * below the max load factor of 0.75 and above the minimum load factor or 0.25.
+ *
+ * @param [in] capacity The minimum number of buckets. Must be greater than 0.
+ *
+ * @return non-NULL A pointer to a valid PARCHashMap instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_CreateCapacity(43);
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_CreateCapacity(unsigned int capacity);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCHashMap instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCHashMap` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * PARCHashMap *copy = parcHashMap_Copy(&b);
+ *
+ * parcHashMap_Release(&b);
+ * parcHashMap_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Copy(const PARCHashMap *original);
+
+/**
+ * Print a human readable representation of the given `PARCHashMap`.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_Display(a, 0);
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+void parcHashMap_Display(const PARCHashMap *instance, int indentation);
+
+/**
+ * Determine if two `PARCHashMap` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCHashMap` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcHashMap_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcHashMap_Equals(x, y)` must return true if and only if
+ * `parcHashMap_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcHashMap_Equals(x, y)` returns true and
+ * `parcHashMap_Equals(y, z)` returns true,
+ * then `parcHashMap_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcHashMap_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcHashMap_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCHashMap instance.
+ * @param [in] y A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ * PARCHashMap *b = parcHashMap_Create();
+ *
+ * if (parcHashMap_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcHashMap_Release(&a);
+ * parcHashMap_Release(&b);
+ * }
+ * @endcode
+ * @see parcHashMap_HashCode
+ */
+bool parcHashMap_Equals(const PARCHashMap *x, const PARCHashMap *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcHashMap_Equals} method,
+ * then calling the {@link parcHashMap_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcHashMap_Equals} function,
+ * then calling the `parcHashMap_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * uint32_t hashValue = parcHashMap_HashCode(buffer);
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcHashMap_HashCode(const PARCHashMap *instance);
+
+/**
+ * Determine if an instance of `PARCHashMap` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * if (parcHashMap_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcHashMap_IsValid(const PARCHashMap *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCHashMap` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+void parcHashMap_Release(PARCHashMap **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * PARCJSON *json = parcHashMap_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcHashMap_ToJSON(const PARCHashMap *instance);
+
+
+PARCBufferComposer *parcHashMap_BuildString(const PARCHashMap *hashMap, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCHashMap`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * char *string = parcHashMap_ToString(a);
+ *
+ * parcHashMap_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcHashMap_Display
+ */
+char *parcHashMap_ToString(const PARCHashMap *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcLinkedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCLinkedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcLinkedList_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcHashMap, PARCHashMap);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcHashMap_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcHashMap_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcHashMap, PARCHashMap);
+
+/**
+ * Obtain the lock on the given `PARCHashMap` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCHashMap` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcHashMap_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcHashMap, PARCHashMap);
+
+/**
+ * Try to obtain the advisory lock on the given PARCHashMap instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The PARCHashMap is locked.
+ * @return false The PARCHashMap is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcHashMap_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcHashMap, PARCHashMap);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCHashMap` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * @return true The `PARCHashMap` was locked and now is unlocked.
+ * @return false The `PARCHashMap` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcHashMap_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcHashMap, PARCHashMap);
+
+/**
+ * Determine if the advisory lock on the given `PARCHashMap` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * @return true The `PARCHashMap` is locked.
+ * @return false The `PARCHashMap` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcHashMap_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcHashMap, PARCHashMap);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Put(PARCHashMap *hashMap, const PARCObject *key, const PARCObject *value);
+
+/**
+ * Returns the value to which the specified key is mapped,
+ * or null if this map contains no mapping for the key.
+ * If this map contains a mapping from a key _k_ to a value _v_ such that `(key==null ? k==null : key.equals(k))`,
+ * then this method returns _v_; otherwise it returns null. (There can be at most one such mapping.)
+ *
+ * A return value of `NULL` does not necessarily indicate that the map contains no mapping for the key.
+ * It is possible that the map explicitly maps the key to `NULL`.
+ * Use the `parcHashMap_ContainsKey` function to distinguish these cases.
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return The value to which the specified key is mapped, or `NULL` if this map contains no mapping for the key
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const PARCObject *parcHashMap_Get(const PARCHashMap *hashMap, const PARCObject *key);
+
+/**
+ * Removes the mapping for the specified key from this `PARCHashMap`, if present.
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The key existed and was removed.
+ * @return true The key did not exist.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcHashMap_Remove(PARCHashMap *hashMap, const PARCObject *key);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t parcHashMap_Size(const PARCHashMap *hashMap);
+
+
+/**
+ * Computes the standard deviation of the PARCHashMap's bucket sizes from a value of 1.0
+ * (as opposed to the mean) and weighs the result by in inverse of the current load
+ * factor. The deviation from 1.0 is used because the hash-map's max load factor is < 1.0
+ * and thus the ideal average chain-length is 1.0.
+ *
+ * A result of 0.0 equates to an ideal distribution, a result of ~1.0 should represent
+ * a fairly normal or random distribution, and a result > 1.5 or so implies some amount
+ * of undesirable clumping may be happening.
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return The clustering number
+ */
+double parcHashMap_GetClusteringNumber(const PARCHashMap *hashMap);
+
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcHashMap_Contains(PARCHashMap *hashMap, const PARCObject *key);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the values of the specified `PARCHashMap`.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCHashMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcHashMap_CreateValueIterator(list);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcHashMap_CreateValueIterator(PARCHashMap *hashMap);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the keys of the specified `PARCHashMap`.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCHashMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcHashMap_CreateKeyIterator(list);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcHashMap_CreateKeyIterator(PARCHashMap *hashMap);
+#endif
diff --git a/libparc/parc/algol/parc_InputStream.c b/libparc/parc/algol/parc_InputStream.c
new file mode 100755
index 00000000..ade5a46a
--- /dev/null
+++ b/libparc/parc/algol/parc_InputStream.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_InputStream.h>
+
+struct parc_input_stream {
+ void *instance;
+ const PARCInputStreamInterface *interface;
+};
+
+static void
+_destroy(PARCInputStream **inputStreamPtr)
+{
+ PARCInputStream *inputStream = *inputStreamPtr;
+ parcObject_Release(&inputStream->instance);
+}
+
+parcObject_ExtendPARCObject(PARCInputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+
+PARCInputStream *
+parcInputStream(void *instance, const PARCInputStreamInterface *interface)
+{
+ PARCInputStream *result = parcObject_CreateInstance(PARCInputStream);
+ result->instance = instance;
+ result->interface = interface;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcInputStream, PARCInputStream);
+
+parcObject_ImplementRelease(parcInputStream, PARCInputStream);
+
+size_t
+parcInputStream_Read(PARCInputStream *inputStream, PARCBuffer *buffer)
+{
+ return (inputStream->interface->Read)(inputStream->instance, buffer);
+}
diff --git a/libparc/parc/algol/parc_InputStream.h b/libparc/parc/algol/parc_InputStream.h
new file mode 100755
index 00000000..3ab6849a
--- /dev/null
+++ b/libparc/parc/algol/parc_InputStream.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_InputStream.h
+ * @ingroup inputoutput
+ * @brief Generalized Input Stream
+ *
+ * a `PARCFileInputStream` is a kind of `PARCInputStream`
+ *
+ */
+#ifndef libparc_parc_InputStream_h
+#define libparc_parc_InputStream_h
+
+#include <parc/algol/parc_Buffer.h>
+
+
+/**
+ * @typedef `PARCInputStream`
+ */
+struct parc_input_stream;
+typedef struct parc_input_stream PARCInputStream;
+
+/**
+ * @typedef PARCInputStreamInterface
+ */
+
+typedef struct parc_input_stream_interface {
+ size_t (*Read)(PARCInputStream *inputStream, PARCBuffer *buffer);
+
+ PARCInputStream *(*Acquire)(const PARCInputStream * instance);
+
+ void (*Release)(PARCInputStream **instancePtr);
+} PARCInputStreamInterface;
+
+/**
+ * Create an instance of a `PARCInputStream` given a pointer to an instance and interface.
+ *
+ *
+ * @param [in] instance A pointer to a structure suitable for the given `PARCInputStreamInterface`.
+ * @param [in] interface A pointer to a `PARCInputStreamInterface`
+ *
+ * @return non-NULL A pointer to a valid PARCInputStream
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCInputStream *parcInputStream(void *instance, const PARCInputStreamInterface *interface);
+
+/**
+ * Read a `PARCInputStream` into a {@link PARCBuffer}.
+ *
+ * The contents of the `PARCBuffer` are filled from the current position to the limit.
+ * When this function returns the position is set to the end of the last successfully read byte of data.
+ *
+ * @param [in] inputStream The `PARCInputStream` to read.
+ * @param [in] buffer The `PARCBuffer` to fill, from the current position of the buffer to its limit.
+ *
+ * @return number of bytes read / filled.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcInputStream_Read(PARCInputStream *inputStream, PARCBuffer *buffer);
+
+/**
+ * Acquire a new reference to an instance of `PARCInputStream`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] instance The instance of `PARCInputStream` to which to refer.
+ *
+ * @return The same value as the input parameter @p instance
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCInputStream *parcInputStream_Acquire(const PARCInputStream *instance);
+
+/**
+ * Release a `PARCInputStream` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCInputStream`.
+ *
+ * @param [in,out] instancePtr is a pointer to the `PARCInputStream` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcInputStream_Release(PARCInputStream **instancePtr);
+#endif // libparc_parc_InputStream_h
diff --git a/libparc/parc/algol/parc_Iterator.c b/libparc/parc/algol/parc_Iterator.c
new file mode 100755
index 00000000..e70a0ff9
--- /dev/null
+++ b/libparc/parc/algol/parc_Iterator.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_iterator {
+ PARCObject *object;
+ void *(*init)(PARCObject *);
+ bool (*hasNext)(PARCObject *, void *);
+ void *(*next)(PARCObject *, void *);
+ void (*remove)(PARCObject *, void **);
+ void *(*element)(PARCObject *, void *);
+ void (*fini)(PARCObject *, void *);
+ void (*assertValid)(const void *);
+ bool initialized;
+ void *state;
+};
+
+static void
+_parcIterator_Destroy(PARCIterator **iteratorPtr)
+{
+ PARCIterator *iterator = *iteratorPtr;
+
+ parcObject_Release(&(iterator->object));
+
+ (iterator->fini(iterator->object, iterator->state));
+}
+
+parcObject_ExtendPARCObject(PARCIterator, _parcIterator_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static void *
+_parcIterator_Init(PARCIterator *iterator)
+{
+ if (iterator->init) {
+ iterator->state = (iterator->init)(iterator->object);
+ }
+
+ if (iterator->assertValid) {
+ (iterator->assertValid)(iterator->state);
+ }
+
+ iterator->initialized = true;
+ return iterator->state;
+}
+
+static void
+_parcIteratorState_AssertValid(const PARCIterator *iterator)
+{
+ if (iterator->assertValid) {
+ (iterator->assertValid)(iterator->state);
+ }
+}
+
+PARCIterator *
+parcIterator_Create(PARCObject *object,
+ void *(*init)(PARCObject *),
+ bool (*hasNext)(PARCObject *, void *),
+ void *(*next)(PARCObject *, void *),
+ void (*remove)(PARCObject *, void **),
+ void *(*element)(PARCObject *, void *),
+ void (*fini)(PARCObject *, void *),
+ void (*assertValid)(const void *))
+{
+ assertNotNull(object, "PARCObject cannot be NULL.");
+ assertNotNull(init, "'init' function cannot be NULL.");
+ assertNotNull(hasNext, "'hasNext' function cannot be NULL.");
+ assertNotNull(next, "'next' function cannot be NULL.");
+ assertNotNull(element, "'element' function cannot be NULL.");
+ assertNotNull(fini, "'fini' function cannot be NULL.");
+
+ PARCIterator *result = parcObject_CreateInstance(PARCIterator);
+
+ if (result != NULL) {
+ result->object = parcObject_Acquire(object);
+ result->init = init;
+ result->hasNext = hasNext;
+ result->next = next;
+ result->remove = remove;
+ result->element = element;
+ result->fini = fini;
+ result->assertValid = assertValid;
+
+ result->initialized = false;
+ _parcIterator_Init(result);
+ }
+
+ return result;
+}
+
+bool
+parcIterator_IsValid(const PARCIterator *iterator)
+{
+ bool result = false;
+
+ if (iterator != NULL) {
+ if (parcObject_IsValid(iterator)) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcIterator_AssertValid(const PARCIterator *iterator)
+{
+ assertTrue(parcIterator_IsValid(iterator), "PARCIterator is not valid.");
+}
+
+parcObject_ImplementAcquire(parcIterator, PARCIterator);
+
+parcObject_ImplementRelease(parcIterator, PARCIterator);
+
+
+void *
+parcIterator_Next(PARCIterator *iterator)
+{
+ parcIterator_OptionalAssertValid(iterator);
+
+ iterator->state = (iterator->next)(iterator->object, iterator->state);
+
+ _parcIteratorState_AssertValid(iterator);
+
+ return (iterator->element)(iterator->object, iterator->state);
+}
+
+bool
+parcIterator_HasNext(const PARCIterator *iterator)
+{
+ parcIterator_OptionalAssertValid(iterator);
+
+ return (iterator->hasNext)(iterator->object, iterator->state);
+}
+
+void
+parcIterator_Remove(PARCIterator *iterator)
+{
+ if (iterator->remove != NULL) {
+ (iterator->remove)(iterator->object, &iterator->state);
+ }
+
+ _parcIteratorState_AssertValid(iterator);
+}
diff --git a/libparc/parc/algol/parc_Iterator.h b/libparc/parc/algol/parc_Iterator.h
new file mode 100644
index 00000000..275a16e7
--- /dev/null
+++ b/libparc/parc/algol/parc_Iterator.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Iterator.h
+ * @ingroup memory
+ * @brief An iterator over any kind of iteratable collection
+ *
+ * Implementations of a PARCIterator must provide the following functions,
+ * each of which supports the operation of the iterator.
+ * @code
+ * _TYPEIterator * PREFIX_Init(TYPE *object)
+ *
+ * bool PREFIX_Fini(TYPE *map, _TYPEIterator *state)
+ *
+ * _PARCHashMapIterator *PREFIX_Next(PARCHashMap *map, _TYPEIterator *state)
+ *
+ * void PREFIX_Remove(PARCHashMap *map, _TYPEIterator **statePtr )
+ *
+ * bool PREFIX_HasNext(PARCHashMap *map, _TYPEIterator *state)
+ *
+ * PARCObject *PREFIX_Element(PARCHashMap *map, const _TYPEIterator *state)
+ *
+ * PARCObject *PREFIX_Element(TYPE *map, const _TYPEIterator *state)
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_Iterator_h
+#define libparc_parc_Iterator_h
+
+#include <stdbool.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_iterator;
+typedef struct parc_iterator PARCIterator;
+
+/**
+ * Create a new instance of `PARCIterator`
+ *
+ * Each instance must be provided pointers to functions implementing the iteration primitives for the given PARCObject.
+ *
+ * * `init`
+ * This function is called only when a PARCIterator is created.
+ * The function is expected to initialise and return a pointer to whatever internal state necessary
+ * to provide the subsequent operations.
+ * In subsequent operations of hasNext, next, getElement, and fini, this pointer is provided as a function parameter.
+ *
+ * * `hasNext`
+ * This function returns true if the iteration has more elements.
+ *
+ * * `next`
+ * Returns the next element in the iteration.
+ * If there are no remaining elements in the iteration, then this function must induce a trapOutOfBounds
+ *
+ * * `remove`
+ * Removes the element returned by the `next` function.
+ *
+ * * `getElement`
+ * This function is invoked only from within the `parcIterator_Next` function and
+ * returns the actual iteration value from the current iterator's state.
+ *
+ * * `fini`
+ * This function is called only when the PARCIterator is being destroyed.
+ *
+ * @param [in] object A pointer to the PARCObject that implements the underlying iteration.
+ * @param [in] hasNext A pointer to a function that returns true if there are more elements.
+ * @param [in] next A pointer to a function that returns the next element.
+ * @param [in] remove A pointer to a function that removes the element last returned by the @p next function.
+ * @param [in] getElement A pointer to a function that, given the current position, return the element at the current position.
+ * @param [in] fini A pointer to a function that will be invoked when the PARCIterator is finally deallocated.
+ * @param [in] isValid A pointer to a function that performs validation of the iterator state.
+ *
+ * @return A `PARCIterator`
+ */
+PARCIterator *parcIterator_Create(PARCObject *object,
+ void *(*init)(PARCObject *object),
+ bool (*hasNext)(PARCObject *object, void *state),
+ void *(*next)(PARCObject *object, void *state),
+ void (*remove)(PARCObject *, void **state),
+ void *(*getElement)(PARCObject *object, void *state),
+ void (*fini)(PARCObject *object, void *state),
+ void (*isValid)(const void *));
+
+/**
+ * Determine if an instance of `PARCIterator` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a `PARCIterator` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *instance = parcIterator_Create(...);
+ *
+ * if (parcIterator_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcIterator_IsValid(const PARCIterator *instance);
+
+/**
+ * Assert that the given `PARCIterator` instance is valid.
+ *
+ * @param [in] iterator A pointer to a valid PARCIterator instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *a = parcIterator_Create(...);
+ *
+ * parcIterator_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcIterator_Release(&b);
+ * }
+ * @endcode
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcIterator_OptionalAssertValid(_instance_)
+#else
+# define parcIterator_OptionalAssertValid(_instance_) parcIterator_AssertValid(_instance_)
+#endif
+void parcIterator_AssertValid(const PARCIterator *iterator);
+
+/**
+ * Increase the number of references to a `PARCIterator`.
+ *
+ * Note that new `PARCIterator` is not created,
+ * only that the given `PARCIterator` reference count is incremented.
+ * Discard the reference by invoking `parcIterator_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCIterator` instance.
+ *
+ * @return The input `PARCIterator` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *a = parcIterator_Create(...);
+ *
+ * PARCIterator *b = parcIterator_Acquire(a);
+ *
+ * parcIterator_Release(&a);
+ * parcIterator_Release(&b);
+ * }
+ * @endcode
+ */
+PARCIterator *parcIterator_Acquire(const PARCIterator *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] iteratorPtr A pointer to a pointer to the instance to release, which will be set to NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *a = parcIterator_Create(...);
+ *
+ * parcIterator_Release(&a);
+ * }
+ * @endcode
+ */
+void parcIterator_Release(PARCIterator **iteratorPtr);
+
+/**
+ * Return the next item in the iterated list
+ *
+ * @param [in] iterator A pointer to the instance of `PARCIterator`
+ *
+ * @return A pointer to the next item in the iterated list
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcIterator_HasNext(iterator)) {
+ * void *element = parcIterator_Next(iterator);
+ * }
+ * }
+ * @endcode
+ */
+void *parcIterator_Next(PARCIterator *iterator);
+
+/**
+ * Return true if there are more items left over which to iterate.
+ *
+ * @param [in] iterator A pointer to the instance of `PARCIterator`
+ *
+ * @return True if there is are more items over which to iterate; false otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcIterator_HasNext(iterator)) {
+ * void *element = parcIterator_Next(iterator);
+ * }
+ * }
+ * @endcode
+ */
+bool parcIterator_HasNext(const PARCIterator *iterator);
+
+/**
+ * Removes from the underlying collection the last element returned by the iterator (optional operation).
+ * This function can be called only once per call to `parcIterator_Next`.
+ * The behavior of an iterator is unspecified if the underlying collection is
+ * modified while the iteration is in progress in any way other than by calling this method.
+ *
+ * Pointers to the element after removing it via this function may point to invalid remnants of the object.
+ * To avoid this, acquire a reference to the element before invoking this function.
+ *
+ * @param [in] iterator A pointer to the instance of `PARCIterator`
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcIterator_HasNext(iterator)) {
+ * void *element = parcIterator_Next(iterator);
+ * }
+ * }
+ * @endcode
+ */
+void parcIterator_Remove(PARCIterator *iterator);
+#endif // libparc_parc_Iterator_h
diff --git a/libparc/parc/algol/parc_JSON.c b/libparc/parc/algol/parc_JSON.c
new file mode 100755
index 00000000..d70a302e
--- /dev/null
+++ b/libparc/parc/algol/parc_JSON.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSONParser.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_PathName.h>
+
+struct parc_json {
+ PARCList *members;
+};
+
+static void
+_destroyPARCJSON(PARCJSON **jsonPtr)
+{
+ PARCJSON *json = *jsonPtr;
+
+ parcList_Release(&json->members);
+}
+
+parcObject_ExtendPARCObject(PARCJSON, _destroyPARCJSON, NULL, parcJSON_ToString, parcJSON_Equals, NULL, NULL, NULL);
+
+PARCJSON *
+parcJSON_Create(void)
+{
+ PARCJSON *result = parcObject_CreateInstance(PARCJSON);
+ if (result != NULL) {
+ result->members = parcList(parcArrayList_Create((void (*)(void **))parcJSONPair_Release), PARCArrayListAsPARCList);
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcJSON, PARCJSON);
+
+parcObject_ImplementRelease(parcJSON, PARCJSON);
+
+static bool
+_memberListEquals(const PARCList *x, const PARCList *y)
+{
+ for (size_t i = 0; i < parcList_Size(x); i++) {
+ PARCJSONPair *pairA = parcList_GetAtIndex(x, i);
+ PARCJSONPair *pairB = parcList_GetAtIndex(y, i);
+ if (parcJSONPair_Equals(pairA, pairB) == false) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static PARCBuffer *
+_toCreatedBuffer(const PARCJSON *json, bool compact)
+{
+ if (json == NULL) {
+ return NULL;
+ }
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSON_BuildString(json, composer, compact);
+
+ PARCBuffer *result = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+static char *
+_toString(const PARCJSON *json, bool compact)
+{
+ PARCBuffer *tempBuffer = _toCreatedBuffer(json, compact);
+
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ return result;
+}
+
+bool
+parcJSON_Equals(const PARCJSON *x, const PARCJSON *y)
+{
+ bool result = false;
+
+ if (x == NULL && y == NULL) {
+ result = true;
+ } else if (x != NULL && y != NULL) {
+ if (parcList_Size(x->members) == parcList_Size(y->members)) {
+ if (_memberListEquals(x->members, y->members)) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcJSON_Copy(const PARCJSON *src)
+{
+ //TODO - This is an ineffecient deep copy. The _Copy() operation needs to be implementd for all PARCJSON* types
+ //before we can do an effecient deep copy.
+ if (src == NULL) {
+ return NULL;
+ }
+ PARCBuffer *temp = _toCreatedBuffer(src, true);
+ PARCJSON *result = parcJSON_ParseBuffer(temp);
+ parcBuffer_Release(&temp);
+
+ return result;
+}
+
+
+PARCHashCode
+parcJSON_HashCode(const PARCJSON *json)
+{
+ PARCBuffer *temp = _toCreatedBuffer(json, true);
+ PARCHashCode result = parcBuffer_HashCode(temp);
+ parcBuffer_Release(&temp);
+
+ return result;
+}
+
+void
+parcJSON_Display(const PARCJSON *json, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSON@%p {", json);
+ for (size_t index = 0; index < parcList_Size(json->members); index++) {
+ PARCJSONPair *pair = parcList_GetAtIndex(json->members, index);
+ parcJSONPair_Display(pair, indentation + 1);
+ }
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+PARCJSONPair *
+parcJSON_GetPairByIndex(const PARCJSON *json, size_t index)
+{
+ PARCJSONPair *result = NULL;
+
+ if (parcList_Size(json->members) > index) {
+ result = parcList_GetAtIndex(json->members, index);
+ }
+
+ return result;
+}
+
+PARCJSONValue *
+parcJSON_GetValueByIndex(const PARCJSON *json, size_t index)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcList_Size(json->members) > index) {
+ result = parcJSONPair_GetValue(parcList_GetAtIndex(json->members, index));
+ }
+
+ return result;
+}
+
+const PARCJSONPair *
+parcJSON_GetPairByName(const PARCJSON *json, const char *name)
+{
+ PARCJSONPair *result = NULL;
+
+ PARCBuffer *nameBuffer = parcBuffer_Wrap((uint8_t *) name, strlen(name), 0, strlen(name));
+ for (size_t index = 0; index < parcList_Size(json->members); index++) {
+ PARCJSONPair *pair = parcList_GetAtIndex(json->members, index);
+ if (parcBuffer_Equals(nameBuffer, parcJSONPair_GetName(pair))) {
+ result = pair;
+ break;
+ }
+ }
+ parcBuffer_Release(&nameBuffer);
+ return result;
+}
+
+PARCJSONValue *
+parcJSON_GetValueByName(const PARCJSON *json, const char *name)
+{
+ PARCJSONValue *result = NULL;
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, name);
+ if (pair != NULL) {
+ result = parcJSONPair_GetValue(pair);
+ }
+
+ return result;
+}
+
+PARCList *
+parcJSON_GetMembers(const PARCJSON *json)
+{
+ return json->members;
+}
+
+PARCBufferComposer *
+parcJSON_BuildString(const PARCJSON *json, PARCBufferComposer *composer, bool compact)
+{
+ parcBufferComposer_PutChar(composer, '{');
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+
+ char *separator = "";
+ for (size_t i = 0; i < parcList_Size(json->members); i++) {
+ parcBufferComposer_PutString(composer, separator);
+ parcJSONPair_BuildString(parcList_GetAtIndex(json->members, i), composer, compact);
+ separator = ", ";
+ if (compact) {
+ separator = ",";
+ }
+ }
+
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+ parcBufferComposer_PutChar(composer, '}');
+ return composer;
+}
+
+
+char *
+parcJSON_ToString(const PARCJSON *json)
+{
+ return _toString(json, false);
+}
+
+char *
+parcJSON_ToCompactString(const PARCJSON *json)
+{
+ return _toString(json, true);
+}
+
+const PARCJSONValue *
+parcJSON_GetByPathName(const PARCJSONValue *pathNode, const PARCPathName *path)
+{
+ for (int i = 0; i < parcPathName_Size(path); i++) {
+ char *name = parcPathName_GetAtIndex(path, i);
+ if (parcJSONValue_IsJSON(pathNode)) {
+ const PARCJSONPair *pair = parcJSON_GetPairByName(parcJSONValue_GetJSON(pathNode), name);
+ if (pair == NULL) {
+ pathNode = NULL;
+ break;
+ }
+ pathNode = parcJSONPair_GetValue(pair);
+ } else if (parcJSONValue_IsArray(pathNode)) {
+ size_t index = strtoll(name, NULL, 10);
+ if (index > parcJSONArray_GetLength(parcJSONValue_GetArray(pathNode))) {
+ pathNode = NULL;
+ break;
+ }
+ pathNode = parcJSONArray_GetValue(parcJSONValue_GetArray(pathNode), index);
+ } else {
+ pathNode = NULL;
+ break;
+ }
+ }
+
+ return pathNode;
+}
+
+const PARCJSONValue *
+parcJSON_GetByPath(const PARCJSON *json, const char *path)
+{
+ PARCJSONValue *pathNode = parcJSONValue_CreateFromJSON((PARCJSON *) json);
+
+ PARCPathName *pathName = parcPathName_Parse(path);
+ const PARCJSONValue *result = parcJSON_GetByPathName(pathNode, pathName);
+ parcPathName_Release(&pathName);
+
+ parcJSONValue_Release(&pathNode);
+ return result;
+}
+
+PARCJSON *
+parcJSON_ParseString(const char *string)
+{
+ // The input string is read-only, therefore we can cast it here when calling the parcBuffer_WrapCString()
+ // to work around the fact that the function does not take a 'const' attribute.
+ // This function is not going to modify the input string, so the 'const' promise will be kept.
+ PARCBuffer *buffer = parcBuffer_WrapCString((char *) string);
+
+ PARCJSON *result = parcJSON_ParseBuffer(buffer);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
+
+PARCJSON *
+parcJSON_ParseBuffer(PARCBuffer *buffer)
+{
+ PARCJSON *result = NULL;
+
+ // The input string is read-only, therefore we can cast it here when calling the parcBuffer_WrapCString()
+ // to work around the fact that the function does not take a 'const' attribute.
+ // This function is not going to modify the input string, so the 'const' promise will be kept.
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ char firstCharacter = parcJSONParser_PeekNextChar(parser);
+ if (firstCharacter == '{') {
+ PARCJSONValue *value = parcJSONValue_ObjectParser(parser);
+
+ result = parcJSON_Acquire(parcJSONValue_GetJSON(value));
+ parcJSONValue_Release(&value);
+ }
+
+ parcJSONParser_Release(&parser);
+
+ return result;
+}
+
+PARCJSON *
+parcJSON_AddPair(PARCJSON *json, PARCJSONPair *pair)
+{
+ parcList_Add(json->members, parcJSONPair_Acquire(pair));
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddValue(PARCJSON *json, const char *name, PARCJSONValue *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddString(PARCJSON *json, const char *name, const char *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromString(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddObject(PARCJSON *json, const char *name, PARCJSON *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSON(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddInteger(PARCJSON *json, const char *name, int64_t value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddBoolean(PARCJSON *json, const char *name, bool value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromBoolean(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddArray(PARCJSON *json, const char *name, PARCJSONArray *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
diff --git a/libparc/parc/algol/parc_JSON.h b/libparc/parc/algol/parc_JSON.h
new file mode 100755
index 00000000..dc8996ca
--- /dev/null
+++ b/libparc/parc/algol/parc_JSON.h
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_JSON.h
+ * @ingroup inputoutput
+ * @brief A complete JSON encoding and decoding library.
+ *
+ * # Parsing #
+ * Parse a null-terminated C string containing JSON via {@link parcJSON_ParseString}.
+ *
+ * # Printing #
+ * Print a JSON object via {@link parcJSON_ToString}.
+ *
+ * # Composing #
+ * Compose JSON objects via {@link parcJSON_Create} and add members via {@link parcJSON_Add}.
+ * Compose members as JSON Pairs consisting of a name and value. See functions named `parcJSONPair_Create*`
+ *
+ */
+#ifndef libparc_parc_JSON_h
+#define libparc_parc_JSON_h
+
+#include <stdbool.h>
+
+struct parc_json;
+typedef struct parc_json PARCJSON;
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_PathName.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONValue.h>
+
+/**
+ * Create a new JSON object.
+ *
+ * The JSON new object contains no members.
+ *
+ * @return A pointer to a `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ * ...
+ * parcJSONValue_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSON_Add}
+ */
+PARCJSON *parcJSON_Create(void);
+
+/**
+ * Create a deep copy of a JSON object. Call parcJSON_Release to free the object when done with it.
+ *
+ * @return A pointer to a `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *jsonSrc = parcJSON_Create();
+ * ...
+ * PARCJSON *jsonCopy = parcJSON_Copy(jsonSrc);
+ * ...
+ * parcJSONValue_Release(&jsonSrc);
+ * ...
+ * parcJSONValue_Release(&jsonCopy);
+ * }
+ * @endcode
+ *
+ */
+PARCJSON *parcJSON_Copy(const PARCJSON *src);
+
+/**
+ * Increase the number of references to a `PARCJSON` instance.
+ *
+ * Note that a new `PARCJSON` is not created,
+ * only that the given `PARCJSON` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSON_Release}.
+ *
+ * @param [in] json A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *x = parcJSON_Create();
+ *
+ * PARCJSON *x2 = parcJSON_Acquire(x);
+ *
+ * parcJSON_Release(&x);
+ * parcJSON_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSON_Release}
+ */
+PARCJSON *parcJSON_Acquire(const PARCJSON *json);
+
+/**
+ * Determine if two `PARCJSON` instances are equal.
+ *
+ * Two `PARCJSON` instances are equal if, and only if,
+ * they contain the equal members, in the same order.
+ *
+ * The following equivalence relations on non-null `PARCJSON` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSON_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcJSON_Equals(x, y)` must return true if and only if
+ * `parcJSON_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSON_Equals(x, y)` returns true and
+ * `parcJSON_Equals(y, z)` returns true,
+ * then `parcJSON_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcJSON_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSON_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCJSON` instance.
+ * @param [in] y A pointer to a `PARCJSON` instance.
+ * @return true if the two `PARCJSON` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *a = parcJSON_Create();
+ * PARCJSON *b = parcJSON_Create();
+ *
+ * if (parcJSON_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcJSON_Equals(const PARCJSON *x, const PARCJSON *y);
+
+/**
+ * Add a JSON Pair to the members of a JSON Object.
+ *
+ * @param [in,out] json A pointer to a `PARCJSON` instance.
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ *
+ * @return The pointer to the `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * PARCJSONPair *pair = parcJSONPair_CreateFromInteger("pi", 314159);
+ * parcJSON_AddPair(json, pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSON *parcJSON_AddPair(PARCJSON *json, PARCJSONPair *pair);
+
+/**
+ * Pretty print the given `PARCJSON` instance.
+ *
+ * @param [in] json The `PARCJSON` instance to be printed.
+ * @param [in] indentation The amount of indentation to prefix each line of output
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * parcJSON_Display(json, 0);
+ * }
+ * @endcode
+ */
+void parcJSON_Display(const PARCJSON *json, int indentation);
+
+/**
+ * Get the list of members of the given `PARCJSON` instance.
+ *
+ * A new reference to the {@link PARCList} is not created.
+ * The caller must create a new reference, if it retains a reference to the buffer.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @return A pointer to a `PARCList` instance containing the members.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * PARCList *members = parcJSON_GetMembers(json);
+ * }
+ * @endcode
+ */
+PARCList *parcJSON_GetMembers(const PARCJSON *json);
+
+/**
+ * Get the PARCJSONPair at the index in the given `PARCJSON` instance.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] index The index value of the desired element.
+ * @return A pointer to a `PARCJSONPair` instance containing or NULL if there is nothing at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * PARCJSONPair *pair = parcJSON_GetPairByIndex(json, 0);
+ * }
+ * @endcode
+ */
+PARCJSONPair *parcJSON_GetPairByIndex(const PARCJSON *json, size_t index);
+
+/**
+ * Get the PARCJSONValue at the index in the given `PARCJSON` instance.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] index The index value of the desired element.
+ * @return A pointer to a `PARCJSONValue` instance containing or NULL if there is nothing at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * PARCJSONValue *pair = parcJSON_GetValueByIndex(json, 0);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSON_GetValueByIndex(const PARCJSON *json, size_t index);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] jsonPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+void parcJSON_Release(PARCJSON **jsonPtr);
+
+/**
+ * Parse a null-terminated C string into a `PARCJSON` instance.
+ *
+ * Only 8-bit characters are parsed.
+ *
+ * @param [in] string A null-terminated C string containing a well-formed JSON object.
+ *
+ * @return A pointer to a `PARCJSON` instance with one reference, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, \"array\" : [1, 2, 3] }");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_ParseString(const char *string);
+
+/**
+ * Parse a null-terminated C string into a `PARCJSON` instance.
+ *
+ * Only 8-bit characters are parsed.
+ *
+ * @param [in] buffer A pointer to a valid PARCBuffer instance.
+ *
+ * @return A pointer to a `PARCJSON` instance with one reference, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufer *buffer = parcBuffer_WrapCString("{ \"key\" : 1, \"array\" : [1, 2, 3] }");
+ * PARCJSON *json = parcJSON_ParseBuffer(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_ParseBuffer(PARCBuffer *buffer);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] json A pointer to the `PARCJSON` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * char *string = parcJSON_ToString(json);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSONPair_BuildString}
+ * @see {@link parcJSONPair_Display}
+ */
+char *parcJSON_ToString(const PARCJSON *json);
+
+/**
+ * Produce a null-terminated compact (minimally escaped and formated) string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] json A pointer to the `PARCJSON` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * char *string = parcJSON_ToCompactString(json);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSONPair_BuildString}
+ * @see {@link parcJSONPair_Display}
+ */
+char *parcJSON_ToCompactString(const PARCJSON *json);
+
+/**
+ * Produce a PARCHashCode for the JSON object.
+ *
+ * @param [in] json A pointer to the `PARCJSON` instance.
+ *
+ * @return PARCHashCode The object's hash-code.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ * ...
+ * PARCHashCode hashCode = parcJSON_HashCode(json);
+ * ....
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ */
+PARCHashCode parcJSON_HashCode(const PARCJSON *json);
+
+/**
+ * Get the {@link PARCJSONPair} with the given key name.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] name A null-terminated C string containing the name of the pair to return.
+ *
+ * @return A pointer to the named `PARCJSONPair`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCJSONPair *arrayPair = parcJSON_GetPairByName(json, "array");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see parcJSON_Add
+ */
+const PARCJSONPair *parcJSON_GetPairByName(const PARCJSON *json, const char *name);
+
+/**
+ * Get the {@link PARCJSONValue} with the given key name.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] name A null-terminated C string containing the name of the pair to return.
+ *
+ * @return A pointer to the named `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCJSONValue *arrayValue = parcJSON_GetValueByName(json, "array");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see parcJSON_Add
+ */
+PARCJSONValue *parcJSON_GetValueByName(const PARCJSON *json, const char *name);
+
+/**
+ * Get the JSON pair named by the given '/' separated path name.
+ *
+ * Using a '/' separated list of JSON pair names, return the {@link PARCJSONPair} named by the path.
+ * This function currently returns the Value, not the Pair specified by the `PARCPathName`
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] path A pointer to a null-terminated C string containing the full path of the `PARCJSONPair`.
+ *
+ * @return A pointer to the {@link PARCJSONValue} named by the path.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCJSONValue *key = parcJSON_GetByPath(json, "/key");
+ *
+ * PARCJSONValue *array_1 = parcJSON_GetByPath(json, "/array/1");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+const PARCJSONValue *parcJSON_GetByPath(const PARCJSON *json, const char *path);
+
+/**
+ * Get the JSON pair named by the given {@link PARCPathName}.
+ * This function currently returns the Value, not the Pair specified by the `PARCPathName`
+ *
+ * @param [in] pathNode A pointer to a {@link PARCJSONValue} instance.
+ * @param [in] pathName A pointer to valid `PARCPathName` instance.
+ *
+ * @return A pointer to the `PARCJSONValue` named by the path.
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCPathName *keyPath = parcPathName_Create("/key");
+ * PARCPathName *array1Path = parcPathName_Create("/array/1");
+ *
+ * PARCJSONValue *key = parcJSON_GetByPathName(json, keyPath);
+ *
+ * PARCJSONValue *array_1 = parcJSON_GetByPathName(json, array1Path);
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+const PARCJSONValue *parcJSON_GetByPathName(const PARCJSONValue *pathNode, const PARCPathName *pathName);
+
+/**
+ * Append a representation of the specified {@link PARCJSON} instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] json A pointer to the `PARCJSON` instance.
+ * @param [in,out] composer A `PARCBufferComposer` to append to this URI segment.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSON_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("JSON String: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSON_BuildString(const PARCJSON *json, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Create and add a JSON string pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value A pointer to a nul-terminated C string containing the value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddString(PARCJSON *json, const char *name, const char *value);
+
+/**
+ * Create and add a JSON object pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value A pointer to a valid `PARCJON` value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddObject(PARCJSON *json, const char *name, PARCJSON *value);
+
+/**
+ * Create and add a pair with an array for the value to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] array A pointer to a valid `PARCJONArray` value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddArray(PARCJSON *json, const char *name, PARCJSONArray *array);
+
+/**
+ * Create and add a pair with a PARCJSONValue for the value to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value A pointer to a valid `PARCJONValue` value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddValue(PARCJSON *json, const char *name, PARCJSONValue *value);
+
+/**
+ * Create and add an integer pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value An integer value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddInteger(PARCJSON *json, const char *name, int64_t value);
+
+/**
+ * Create and add a boolean pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value An boolean value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddBoolean(PARCJSON *json, const char *name, bool value);
+
+/**
+ * Create and add a boolean pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value An boolean value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddArray(PARCJSON *json, const char *name, PARCJSONArray *value);
+#endif // libparc_parc_JSON_h
diff --git a/libparc/parc/algol/parc_JSONArray.c b/libparc/parc/algol/parc_JSONArray.c
new file mode 100755
index 00000000..87421e12
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONArray.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_JSONArray.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parcJSONArray {
+ PARCDeque *array;
+};
+
+static void
+_destroy(PARCJSONArray **arrayPtr)
+{
+ PARCJSONArray *array = *arrayPtr;
+ // Un-reference the JSONValue instances here because parcDeque doesn't (yet) acquire and release its own references.
+
+ for (int i = 0; i < parcDeque_Size(array->array); i++) {
+ PARCJSONValue *value = parcDeque_GetAtIndex(array->array, i);
+ parcJSONValue_Release(&value);
+ }
+ parcDeque_Release(&array->array);
+}
+
+parcObject_ExtendPARCObject(PARCJSONArray, _destroy, NULL, parcJSONArray_ToString, parcJSONArray_Equals, NULL, NULL, NULL);
+
+static const PARCObjectDescriptor parcArrayValue_ObjInterface = {
+ .destroy = (PARCObjectDestroy *) parcJSONValue_Release,
+ .toString = (PARCObjectToString *) parcJSONValue_ToString,
+ .equals = (PARCObjectEquals *) parcJSONValue_Equals
+};
+
+void
+parcJSONArray_AssertValid(const PARCJSONArray *array)
+{
+ assertNotNull(array, "Must be a non-null pointer to a PARCJSONArray instance.");
+ assertNotNull(array->array, "Must be a non-null pointer to a PARCDeque instance.");
+}
+
+PARCJSONArray *
+parcJSONArray_Create(void)
+{
+ PARCJSONArray *result = parcObject_CreateInstance(PARCJSONArray);
+ result->array = parcDeque_CreateObjectInterface(&parcArrayValue_ObjInterface);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcJSONArray, PARCJSONArray);
+
+parcObject_ImplementRelease(parcJSONArray, PARCJSONArray);
+
+bool
+parcJSONArray_Equals(const PARCJSONArray *x, const PARCJSONArray *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ result = parcDeque_Equals(x->array, y->array);
+ }
+ return result;
+}
+
+PARCJSONArray *
+parcJSONArray_AddValue(PARCJSONArray *array, PARCJSONValue *value)
+{
+ parcDeque_Append(array->array, parcJSONValue_Acquire(value));
+ return array;
+}
+
+size_t
+parcJSONArray_GetLength(const PARCJSONArray *array)
+{
+ return parcDeque_Size(array->array);
+}
+
+PARCJSONValue *
+parcJSONArray_GetValue(const PARCJSONArray *array, size_t index)
+{
+ return (PARCJSONValue *) parcDeque_GetAtIndex(array->array, index);
+}
+
+PARCBufferComposer *
+parcJSONArray_BuildString(const PARCJSONArray *array, PARCBufferComposer *composer, bool compact)
+{
+#ifdef hasPARCIterator
+ PARCIterator *iterator = parcDeque_GetIterator(array->array);
+
+ parcBufferComposer_PutChar(composer, '[');
+
+ char *separator = "";
+
+ for (i = parcIterator_Start(); i < parcIterator_Limit(iterator); i = parcIterator_Next(iterator)) {
+ PARCJSONValue *value = parcIterator_Get(iterator);
+ parcBufferComposer_PutString(composer, separator);
+ separator = ", ";
+ if (compact) {
+ separator = ",";
+ }
+
+ parcJSONValue_BuildString(value, composer);
+ }
+ parcBufferComposer_PutChar(composer, ']');
+#else
+ parcBufferComposer_PutChar(composer, '[');
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+
+ char *separator = "";
+
+ for (int i = 0; i < parcDeque_Size(array->array); i++) {
+ PARCJSONValue *value = parcDeque_GetAtIndex(array->array, i);
+ parcBufferComposer_PutString(composer, separator);
+
+ parcJSONValue_BuildString(value, composer, compact);
+ separator = ", ";
+ if (compact) {
+ separator = ",";
+ }
+ }
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+ parcBufferComposer_PutChar(composer, ']');
+#endif
+ return composer;
+}
+
+void
+parcJSONArray_Display(const PARCJSONArray *array, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSONArray@%p {", array);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+static char *
+_parcJSONArray_ToString(const PARCJSONArray *array, bool compact)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcJSONArray_BuildString(array, composer, compact);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+char *
+parcJSONArray_ToString(const PARCJSONArray *array)
+{
+ return _parcJSONArray_ToString(array, false);
+}
+
+char *
+parcJSONArray_ToCompactString(const PARCJSONArray *array)
+{
+ return _parcJSONArray_ToString(array, true);
+}
diff --git a/libparc/parc/algol/parc_JSONArray.h b/libparc/parc/algol/parc_JSONArray.h
new file mode 100755
index 00000000..32fa9817
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONArray.h
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_JSONArray.h
+ * @brief A JSON Array stores an array of JSON objects.
+ * @ingroup inputoutput
+ *
+ */
+#ifndef libparc_parc_JSONArray_h
+#define libparc_parc_JSONArray_h
+
+struct parcJSONArray;
+typedef struct parcJSONArray PARCJSONArray;
+
+#include <parc/algol/parc_JSONValue.h>
+
+/**
+ * Create an empty `PARCJSONArray` instance.
+ *
+ * @return A pointer to an empty `PARCJSONArray` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ * parcJSONArray_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see parcJSONArray_AddValue
+ */
+PARCJSONArray *parcJSONArray_Create(void);
+
+/**
+ * Increase the number of references to a `PARCJSONArray`.
+ *
+ * Note that new `PARCJSONArray` is not created,
+ * only that the given `PARCJSONArray` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSONArray_Release}.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ *
+ * @return The input `PARCJSONArray` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ *
+ * PARCJSONArray *x_2 = parcJSONArray_Acquire(x);
+ *
+ * parcJSONArray_Release(&x);
+ * parcJSONArray_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCJSONArray *parcJSONArray_Acquire(const PARCJSONArray *array);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] arrayPtr A pointer to a pointer to the instance of `PARCJSONArray` to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ *
+ * parcJSONArray_Release(&x);
+ * }
+ * @endcode
+ */
+void parcJSONArray_Release(PARCJSONArray **arrayPtr);
+
+/**
+ * Assert that an instance of `PARCJSONArray` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ */
+void parcJSONArray_AssertValid(const PARCJSONArray *array);
+
+/**
+ * Determine if two `PARCJSONArray` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCJSONArray` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSONArray_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcJSONArray_Equals(x, y)` must return true if and only if
+ * `parcJSONArray_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSONArray_Equals(x, y)` returns true and
+ * `parcJSONArray_Equals(y, z)` returns true,
+ * then `parcJSONArray_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcJSONArray_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSONArray_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a `PARCJSONArray` instance.
+ * @param [in] y A pointer to a `PARCJSONArray` instance.
+ *
+ * @return true `PARCJSONArray` x and y are equal.
+ * @return false `PARCJSONArray` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ * PARCJSONArray *y = parcJSONArray_Create();
+ *
+ * if (parcJSONArray_Equals(x, y)) {
+ * printf("Arrays are equal.\n");
+ * } else {
+ * printf("Arrays are NOT equal.\n");
+ * }
+ *
+ * parcJSONArray_Release(&x);
+ * parcJSONArray_Release(&y);
+ * }
+ * @endcode
+ */
+bool parcJSONArray_Equals(const PARCJSONArray *x, const PARCJSONArray *y);
+
+/**
+ * Add {@link PARCJSONValue} instance to the given `PARCJSONArray`.
+ *
+ * A new reference to the `PARCJSONValue` is acquired by this call.
+ *
+ * @param [in,out] array A pointer to a `PARCJSONArray` instance.
+ * @param [in] value A pointer to a `PARCJSONValue` instance.
+ *
+ * @return A pointer to the @p array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ *
+ */
+PARCJSONArray *parcJSONArray_AddValue(PARCJSONArray *array, PARCJSONValue *value);
+
+/**
+ * Get the length of the given `PARCJSONArray` instance.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ *
+ * @return The number of elements in the array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * parcJSONValue_GetLength(array);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ */
+size_t parcJSONArray_GetLength(const PARCJSONArray *array);
+
+/**
+ * Get the {@link PARCJSONValue} stored at the given index in the `PARCJSONArray`.
+ * A new reference is not acquired.
+ * The caller must acquire its own reference if needed.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ * @param [in] index The index of the `PARCJSONValue` to get.
+ *
+ * @return The pointer to the requested `PARCJSONValue`, or NULL if the index exceeded the length of the array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * PARCJSONValue *actualValue = parcJSONValue_GetValue(array, 0);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONArray_GetValue(const PARCJSONArray *array, size_t index);
+
+/**
+ * Append a representation of the specified `PARCJSONArray` instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] array A pointer to the `PARCJSONArray` instance.
+ * @param [in,out] composer A pointer to the `PARCBufferComposer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSONArray_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("JSON Array: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSONArray_BuildString(const PARCJSONArray *array, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] array A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * const char *string = parcJSONValue_ToString(array);
+ *
+ * parcMemory_Deallocate((void **) &string);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ *
+ * @see parcJSONArray_Display
+ */
+char *parcJSONArray_ToString(const PARCJSONArray *array);
+
+/**
+ * Produce a null-terminated compact string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] array A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * const char *string = parcJSONValue_ToCompactString(array);
+ *
+ * parcMemory_Deallocate((void **) &string);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ *
+ * @see parcJSONArray_Display
+ */
+char *parcJSONArray_ToCompactString(const PARCJSONArray *array);
+
+/**
+ * Pretty print the given `PARCJSONArray` instance.
+ *
+ * @param [in] array The `PARCJSONArray` instance to be printed.
+ * @param [in] indentation The amount of indentation to prefix each line of output
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * parcJSONArray_Display(array, 0);
+ * }
+ * @endcode
+ */
+void parcJSONArray_Display(const PARCJSONArray *array, int indentation);
+#endif // libparc_parc_JSONArray_h
diff --git a/libparc/parc/algol/parc_JSONPair.c b/libparc/parc/algol/parc_JSONPair.c
new file mode 100755
index 00000000..a5df700f
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONPair.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This does not properly implement the equals contract because the JSON object is stored in a PARCArrayList,
+ * which cannot compare elements other than by equal memory address.
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSONParser.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+struct parcJSONPair {
+ PARCBuffer *name;
+ PARCJSONValue *value;
+};
+
+static void
+_destroyJSONPair(PARCJSONPair **pairPtr)
+{
+ if (pairPtr != NULL) {
+ PARCJSONPair *pair = *pairPtr;
+ assertNotNull(pair, "Parameter must be a non-null pointer to a valid PARCJSONPair.");
+ parcBuffer_Release(&pair->name);
+ parcJSONValue_Release(&pair->value);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCJSONPair, _destroyJSONPair, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCJSONPair *
+_createJSONPair(void)
+{
+ return parcObject_CreateInstance(PARCJSONPair);
+}
+
+PARCJSONPair *
+parcJSONPair_Create(const PARCBuffer *name, PARCJSONValue *value)
+{
+ PARCJSONPair *result = _createJSONPair();
+ if (result != NULL) {
+ result->name = parcBuffer_Acquire(name);
+ result->value = parcJSONValue_Acquire(value);
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcJSONPair, PARCJSONPair);
+
+parcObject_ImplementRelease(parcJSONPair, PARCJSONPair);
+
+void
+parcJSONPair_Display(const PARCJSONPair *pair, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSONPair@%p {", pair);
+ parcBuffer_Display(pair->name, indentation + 1);
+ parcJSONValue_Display(pair->value, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+PARCBuffer *
+parcJSONPair_GetName(const PARCJSONPair *pair)
+{
+ return pair->name;
+}
+
+PARCJSONValue *
+parcJSONPair_GetValue(const PARCJSONPair *pair)
+{
+ return pair->value;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromJSONValue(const char *name, PARCJSONValue *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONPair *result = parcJSONPair_Create(nameBuffer, value);
+ parcBuffer_Release(&nameBuffer);
+
+ return result;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromString(const char *name, const char *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+
+ PARCBuffer *valueBuffer = parcBuffer_AllocateCString(value);
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(valueBuffer);
+ parcBuffer_Release(&valueBuffer);
+
+ PARCJSONPair *result = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return result;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromNULL(const char *name)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromNULL();
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromBoolean(const char *name, bool value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromBoolean(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromInteger(const char *name, int64_t value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromInteger(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromDouble(const char *name, double value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromFloat(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromJSONArray(const char *name, PARCJSONArray *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromJSONArray(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromJSON(const char *name, PARCJSON *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromJSON(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+bool
+parcJSONPair_Equals(const PARCJSONPair *objA, const PARCJSONPair *objB)
+{
+ if (objA == NULL && objB == NULL) {
+ return true;
+ } else if (objA != NULL && objB != NULL) {
+ if (parcBuffer_Equals(objA->name, objB->name)) {
+ if (parcJSONValue_Equals(objA->value, objB->value)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+PARCBufferComposer *
+parcJSONPair_BuildString(const PARCJSONPair *pair, PARCBufferComposer *composer, bool compact)
+{
+ parcBufferComposer_PutUint8(composer, '"');
+
+ parcBufferComposer_PutBuffer(composer, pair->name);
+ parcBuffer_Rewind(pair->name);
+ if (compact) {
+ parcBufferComposer_PutString(composer, "\":");
+ } else {
+ parcBufferComposer_PutString(composer, "\" : ");
+ }
+ parcJSONValue_BuildString(pair->value, composer, compact);
+
+ return composer;
+}
+
+char *
+parcJSONPair_ToString(const PARCJSONPair *pair)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcJSONPair_BuildString(pair, composer, false);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+PARCJSONPair *
+parcJSONPair_Parser(PARCJSONParser *parser)
+{
+ PARCJSONPair *result = NULL;
+
+ // This makes an unnecessary copy. I think this could just be a buffer slice.
+ PARCBuffer *name = parcJSONParser_ParseString(parser);
+ char c = parcJSONParser_NextChar(parser);
+ if (c == ':') {
+ PARCJSONValue *value = parcJSONValue_Parser(parser);
+ if (value != NULL) {
+ result = parcJSONPair_Create(name, value);
+ parcJSONValue_Release(&value);
+ }
+ }
+ parcBuffer_Release(&name);
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_JSONPair.h b/libparc/parc/algol/parc_JSONPair.h
new file mode 100755
index 00000000..dff8485b
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONPair.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_JSON.h
+ * @ingroup inputoutput
+ * @brief JSON A JSON pair consists of a name and a value separated by a colon.
+ *
+ */
+#ifndef libparc_parc_JSONPair_h
+#define libparc_parc_JSONPair_h
+
+#include <stdbool.h>
+
+struct parcJSONPair;
+typedef struct parcJSONPair PARCJSONPair;
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_List.h>
+
+#include <parc/algol/parc_JSONArray.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSONParser.h>
+
+/**
+ * Create a new JSON Pair
+ *
+ * @param [in] name A pointer to a {@link PARCBuffer} instance containing the name for the JSON Pair.
+ * @param [in] value A pointer to a {@link PARCJSONValue} instance containing the value for the JSON Pair.
+ * @return A pointer to a new `PARCJSONPair`, or NULL if an error occured.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *name = parcBuffer_AllocateCString("myname");
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSONPair_CreateFromString}
+ * @see {@link parcJSONPair_CreateFromNULL}
+ * @see {@link parcJSONPair_CreateFromBoolean}
+ * @see {@link parcJSONPair_CreateFromInteger}
+ * @see {@link parcJSONPair_CreateFromDouble}
+ * @see {@link parcJSONPair_CreateFromJSONArray}
+ * @see {@link parcJSONPair_CreateFromJSON}
+ */
+PARCJSONPair *parcJSONPair_Create(const PARCBuffer *name, PARCJSONValue *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and value represented as null-terminated C strings.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a null-terminated C string for the value of the `PARCJSONPair`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromString("name", "value");
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromString(const char *name, const char *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and `PARCJSONValue`.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a `PARCJSONValue` for the value of the `PARCJSONPair`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue("name", "value");
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromJSONValue(const char *name, PARCJSONValue *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and the null value.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromNULL("name");
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromNULL(const char *name);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON boolean of true or false as the value.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value Either `true` or `false`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromBoolean("name", true);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromBoolean(const char *name, bool value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON Integer.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value An integer value.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromInteger("name", 314159);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromInteger(const char *name, int64_t value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON floating point value.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A double value.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromDouble(const char *name, double value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON Array.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a {@link PARCJSONArray} instance for the value.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ * PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray("name", array);
+ * parcJSONArray_Release(&array);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromJSONArray(const char *name, PARCJSONArray *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON Object.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a {@link PARCJSON} instance.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json parcJSON_Create();
+ * PARCJSONPair *pair = parcJSONPair_CreateFromJSON("name", json);
+ * parcJSON_Release(&json);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromJSON(const char *name, PARCJSON *value);
+
+/**
+ * Increase the number of references to a `PARCJSONPair` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking {@link parcJSONPair_Release}.
+ *
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ * @return A pointer to the original instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * PARJSON *reference = parcJSONPair_Acquire(pair);
+ *
+ * parcJSONPair_Release(&pair);
+ * parcJSONPair_Release(&reference);
+ * }
+ * @endcode
+ */
+PARCJSONPair *parcJSONPair_Acquire(const PARCJSONPair *pair);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * The contents of the deallocated memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] pairPtr A pointer to a pointer to the `PARCJSONPair` instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ */
+void parcJSONPair_Release(PARCJSONPair **pairPtr);
+
+/**
+ * Get the {@link PARCBuffer} containing the name of the given `PARCJSONPair`.
+ *
+ * A new reference to the `PARCBuffer` is not created.
+ * The caller must create a new reference, if it retains a reference to the buffer.
+ *
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ *
+ * @return A pointer to a `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * const char *name = parcJSONPair_GetName(pair);
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCBuffer *parcJSONPair_GetName(const PARCJSONPair *pair);
+
+/**
+ * Print a human readable representation of the given `PARCJSONPair`.
+ *
+ * @param [in] pair A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ * parcJSONPair_Display(pair, 0);
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ */
+void parcJSONPair_Display(const PARCJSONPair *pair, int indentation);
+
+/**
+ * Get the {@link PARCJSONValue} containing the value of the given `PARCJSONPair`.
+ *
+ * A new reference to the `PARCJSONValue` is not created.
+ * The caller must create a new reference, if it retains a reference to the value instance.
+ *
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ *
+ * @return A pointer to a `PARCJSONValue` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ * PARCJSONValue *value = parcJSONPair_GetValue(pair);
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONValue *parcJSONPair_GetValue(const PARCJSONPair *pair);
+
+/**
+ * Determine if two `PARCJSONPair` instances are equal.
+ *
+ * Two `PARCJSONPair` instances are equal if, and only if, their names and values are equal.
+ *
+ * The following equivalence relations on non-null `PARCJSONPair` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSONPair_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcJSONPair_Equals(x, y)` must return true if and only if
+ * `parcJSONPair_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSONPair_Equals(x, y)` returns true and
+ * `parcJSONPair_Equals(y, z)` returns true,
+ * then `parcJSONPair_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcJSONPair_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSONPair_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCJSONPair` instance.
+ * @param [in] y A pointer to a `PARCJSONPair` instance.
+ * @return true if the two `PARCJSONPair` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *a = parcJSONPair_Equals();
+ * PARCJSONPair *b = parcJSONPair_Equals();
+ *
+ * if (parcJSONPair_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcJSONPair_Equals(const PARCJSONPair *x, const PARCJSONPair *y);
+
+/**
+ * Produce a null-terminated string representation of the specified instance of `PARCJSONPair`.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] pair A pointer to the `PARCJSONPair` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(123456);
+ * PARCJSONPair *instance = parcJSONPair_Create(parcBuffer_Wrap("Hello", 5, 0, 5), value);
+ * parcJSONValue_Release(&value);
+ *
+ * char *string = parcJSONPair_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("%s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSONPair_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_BuildString
+ * @see parcJSONPair_Display
+ */
+char *parcJSONPair_ToString(const PARCJSONPair *pair);
+
+/**
+ * Append a representation of the specified instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] pair A pointer to the `PARCJSONPair` instance.
+ * @param [in,out] composer A pointer to the `PARCBufferComposer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSONPair_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("Hello: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSONPair_BuildString(const PARCJSONPair *pair, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Parse a complete JSON pair
+ *
+ * A pair consists of a name and a value separated by a colon.
+ *
+ * @param [in] parser A pointer to a {@link PARCJSONParser} instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONPair`
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("\"name\" : \"value\"");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONPair *pair = parcJSONPair_Parser(parser);
+ *
+ * parcJSONPair_Release(&pair);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCJSONPair *parcJSONPair_Parser(PARCJSONParser *parser);
+#endif // libparc_parc_JSONPair_h
diff --git a/libparc/parc/algol/parc_JSONParser.c b/libparc/parc/algol/parc_JSONParser.c
new file mode 100755
index 00000000..a0022597
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONParser.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include <parc/algol/parc_JSONParser.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_buffer_parser {
+ char *ignore;
+ PARCBuffer *buffer;
+};
+
+static PARCBuffer *
+_getBuffer(const PARCJSONParser *parser)
+{
+ return parser->buffer;
+}
+
+static void
+_destroyPARCBufferParser(PARCJSONParser **instancePtr)
+{
+ PARCJSONParser *parser = *instancePtr;
+ parcBuffer_Release(&parser->buffer);
+}
+
+parcObject_ExtendPARCObject(PARCJSONParser, _destroyPARCBufferParser, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCJSONParser *
+parcJSONParser_Create(PARCBuffer *buffer)
+{
+ PARCJSONParser *result = parcObject_CreateInstance(PARCJSONParser);
+ result->ignore = " \t\n";
+ result->buffer = parcBuffer_Acquire(buffer);
+ return result;
+}
+
+void
+parcJSONParser_AssertValid(const PARCJSONParser *parser)
+{
+ assertNotNull(parser, "PARCJSONParser cannot be NULL");
+ parcBuffer_OptionalAssertValid(parser->buffer);
+}
+
+parcObject_ImplementAcquire(parcJSONParser, PARCJSONParser);
+
+parcObject_ImplementRelease(parcJSONParser, PARCJSONParser);
+
+void
+parcJSONParser_SkipIgnored(PARCJSONParser *parser)
+{
+ parcJSONParser_OptionalAssertValid(parser);
+
+ parcBuffer_SkipOver(parser->buffer, strlen(parser->ignore), (uint8_t *) parser->ignore);
+}
+
+char
+parcJSONParser_NextChar(PARCJSONParser *parser)
+{
+ parcJSONParser_SkipIgnored(parser);
+ return (char) parcBuffer_GetUint8(parser->buffer);
+}
+
+bool
+parcJSONParser_Next(PARCJSONParser *parser, char *value)
+{
+ bool result = false;
+ parcJSONParser_SkipIgnored(parser);
+ if (parcJSONParser_Remaining(parser) > 0) {
+ *value = (char) parcBuffer_GetUint8(parser->buffer);
+ result = true;
+ }
+ return result;
+}
+
+char
+parcJSONParser_PeekNextChar(PARCJSONParser *parser)
+{
+ parcJSONParser_SkipIgnored(parser);
+ return (char) parcBuffer_PeekByte(parser->buffer);
+}
+
+void
+parcJSONParser_Advance(PARCJSONParser *parser, long bytes)
+{
+ parcJSONParser_OptionalAssertValid(parser);
+
+ parcBuffer_SetPosition(parser->buffer, parcBuffer_Position(parser->buffer) + bytes);
+}
+
+size_t
+parcJSONParser_Remaining(const PARCJSONParser *parser)
+{
+ parcJSONParser_OptionalAssertValid(parser);
+
+ return parcBuffer_Remaining(parser->buffer);
+}
+
+bool
+parcJSONParser_RequireString(PARCJSONParser *parser, const char *string)
+{
+ PARCBuffer *buffer = _getBuffer(parser);
+
+ for (const char *requiredCharacter = string; *requiredCharacter != 0; requiredCharacter++) {
+ uint8_t actualCharacter = parcBuffer_GetUint8(buffer);
+ if (actualCharacter != *requiredCharacter) {
+ return false;
+ }
+ }
+ return true;
+}
+
+PARCBuffer *
+parcJSONParser_ParseString(PARCJSONParser *parser)
+{
+ PARCBuffer *result = NULL;
+
+ PARCBuffer *buffer = _getBuffer(parser);
+ if (parcBuffer_GetUint8(buffer) == '"') { // skip the initial '"' character starting the string.
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ while (parcBuffer_Remaining(buffer)) {
+ uint8_t c = parcBuffer_GetUint8(buffer);
+ if (c == '"') {
+ // This is the only successful way to exit this while loop.
+ result = parcBufferComposer_ProduceBuffer(composer);
+ break;
+ } else if (c == '\\') {
+ c = parcBuffer_GetUint8(buffer);
+ if (c == '"') {
+ // this special character passes directly into the composed string.
+ } else if (c == '\\') {
+ // this special character passes directly into the composed string.
+ } else if (c == '/') {
+ // this special character passes directly into the composed string.
+ } else if (c == 'b') {
+ c = '\b';
+ } else if (c == 'f') {
+ c = '\f';
+ } else if (c == 'n') {
+ c = '\n';
+ } else if (c == 'r') {
+ c = '\r';
+ } else if (c == 't') {
+ c = '\t';
+ } else if (c == 'u') {
+ // Not supporting unicode at this point.
+ trapNotImplemented("Unicode is not supported.");
+ }
+ } else if (iscntrl(c)) {
+ // !! Syntax Error.
+ break;
+ }
+ parcBufferComposer_PutChar(composer, c);
+ }
+
+ parcBufferComposer_Release(&composer);
+ }
+ return result;
+}
diff --git a/libparc/parc/algol/parc_JSONParser.h b/libparc/parc/algol/parc_JSONParser.h
new file mode 100755
index 00000000..18ee9d1a
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONParser.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_JSONParser.h
+ * @brief A JSON parser
+ * @ingroup inputoutput
+ *
+ */
+#ifndef PARC_Library_parc_JSONParser_h
+#define PARC_Library_parc_JSONParser_h
+
+struct parc_buffer_parser;
+typedef struct parc_buffer_parser PARCJSONParser;
+
+#include <parc/algol/parc_Buffer.h>
+
+/**
+ * @def parcJSONValue_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to nullify validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcJSONParser_OptionalAssertValid(_instance_)
+#else
+# define parcJSONParser_OptionalAssertValid(_instance_) parcJSONParser_AssertValid(_instance_)
+#endif
+
+
+/**
+ * Create a new `PARCJSONParser`.
+ *
+ * @param [in] buffer A pointer to a {@link PARCBuffer} containing the data to parse.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONParser`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ *
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCJSONParser *parcJSONParser_Create(PARCBuffer *buffer);
+
+/**
+ * Assert that an instance of `PARCJSONParser` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue()}
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ */
+void parcJSONParser_AssertValid(const PARCJSONParser *parser);
+
+/**
+ * Increase the number of references to a `PARCJSONParser`.
+ *
+ * Note that new `PARCJSONParser` is not created,
+ * only that the given `PARCJSONParser` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSONParser_Release}.
+ *
+ * @param parser A pointer to the original instance.
+ * @return The value of the input parameter @p parser.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONParser *x2 = parcJSONParser_Acquire(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * parcJSONParser_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcJSONParser_Release
+ */
+PARCJSONParser *parcJSONParser_Acquire(const PARCJSONParser *parser);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] parserPtr A pointer to a pointer to the instance of `PARCJSONParser` to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+void parcJSONParser_Release(PARCJSONParser **parserPtr);
+
+/**
+ * Advance the parser, skipping any ignored characters.
+ *
+ * Ignored characters are space, tab and new-line.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcJSONParser_SkipIgnored(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+void parcJSONParser_SkipIgnored(PARCJSONParser *parser);
+
+/**
+ * Get the next character from the parser.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * @return The next character
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * char c = parcJSONParser_NextChar(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+char parcJSONParser_NextChar(PARCJSONParser *parser);
+
+/**
+ * Get the next character from the parser, returning true or false if successful.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ * @param [out] value A pointer to a `char` to contain the value if successful.
+ *
+ * @return true If successful
+ * @return false If unsuccessful
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * bool success = parcJSONParser_Next(parser, &c);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+bool parcJSONParser_Next(PARCJSONParser *parser, char *value);
+
+/**
+ * Get the next character that the parser will process, but do not process it nor advance the parser.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * @return The next character that the parser will process.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * char c = parcJSONParser_PeekNextChar(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+char parcJSONParser_PeekNextChar(PARCJSONParser *parser);
+
+/**
+ * Advance the position of the parser forward or backward by the given number of bytes.
+ *
+ * To advance forward, bytes is a positive value.
+ * To advance backwards, bytes is a negative value.
+ *
+ * @param [in] parser A pointer to a valid `PARCJSONParser`.
+ * @param [in] bytes The number of bytes to move forward or backward.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("abcdef");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcJSONParser_Advance(parser, 2);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+void parcJSONParser_Advance(PARCJSONParser *parser, long bytes);
+
+/**
+ * Get the number of characters remaining to be parsed.
+ *
+ * @param [in] parser A pointer to a valid `PARCJSONParser` instance
+ *
+ * @return The number of characters remaining to be parsed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("true);
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * size_t remaining = parcJSONParser_Remaining(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+size_t parcJSONParser_Remaining(const PARCJSONParser *parser);
+
+/**
+ * Require the fixed string to appear in the current position of the parser.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ * @param [in] string A pointer to a null-terminated C-string that must appear at the current position of the parser.
+ *
+ * @return true If the string appears.
+ * @return false If the string does not appear
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("true");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * bool result = parcJSONParser_RequireString(parser, "true");
+ *
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+bool parcJSONParser_RequireString(PARCJSONParser *parser, const char *string);
+
+/**
+ * Parse a JSON string returning a {@link PARCBuffer} containing the parsed string.
+ *
+ * A JSON string begins and ends with a non-escaped double-quote character.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCBuffer`.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("\"name\" : 123");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCBuffer *theName = parcJSONParser_ParseString(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcJSONParser_ParseString(PARCJSONParser *parser);
+
+#endif
diff --git a/libparc/parc/algol/parc_JSONValue.c b/libparc/parc/algol/parc_JSONValue.c
new file mode 100755
index 00000000..3a3ba9cd
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONValue.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+
+typedef enum {
+ PARCJSONValueType_Boolean,
+ PARCJSONValueType_String,
+ PARCJSONValueType_Number,
+ PARCJSONValueType_Array,
+ PARCJSONValueType_JSON,
+ PARCJSONValueType_Null
+} _PARCJSONValueType;
+
+struct parc_json_value {
+ _PARCJSONValueType type;
+
+ union {
+ bool boolean;
+ PARCBuffer *string;
+ int64_t intValue;
+ PARCList *_array;
+ PARCJSONArray *array;
+ PARCJSON *object;
+ struct {
+ bool internalDoubleRepresentation;
+ long double internalDoubleValue;
+
+ int sign;
+ int64_t whole;
+ int64_t fraction;
+ int64_t fractionLog10;
+ int64_t exponent;
+ } number;
+ } value;
+};
+
+
+
+static void
+_parcJSONValueDestroy(PARCJSONValue **valuePtr)
+{
+ if (valuePtr != NULL) {
+ PARCJSONValue *value = *valuePtr;
+ if (value->type == PARCJSONValueType_Array) {
+ parcJSONArray_Release(&value->value.array);
+ } else if (value->type == PARCJSONValueType_JSON) {
+ parcJSON_Release(&value->value.object);
+ } else if (value->type == PARCJSONValueType_String) {
+ parcBuffer_Release(&value->value.string);
+ }
+ }
+}
+
+parcObject_ExtendPARCObject(PARCJSONValue, _parcJSONValueDestroy, NULL, NULL, parcJSONValue_Equals, NULL, NULL, NULL);
+
+static PARCJSONValue *
+_createValue(_PARCJSONValueType type)
+{
+ PARCJSONValue *result = parcObject_CreateAndClearInstance(PARCJSONValue);
+
+ if (result != NULL) {
+ result->type = type;
+ }
+ return result;
+}
+
+/**
+ * Return true if the parser is currently positioned at the valid beginning of a number.
+ * If true, then return the sign (-1, +1) in the integer pointed to by @p sign.
+ * If false, then return false ensuring that the parser is repositioned to where it started.
+ */
+static bool
+_parseSign(PARCJSONParser *parser, int *sign)
+{
+ if (parcJSONParser_Remaining(parser) > 0) {
+ uint8_t c = parcJSONParser_NextChar(parser);
+ if (c == '-') {
+ *sign = -1;
+ return true;
+ }
+ if (!isdigit(c)) {
+ return false;
+ }
+ parcJSONParser_Advance(parser, -1);
+ }
+ *sign = 1;
+ return true;
+}
+
+static PARCJSONValue *
+_parcJSONValue_FalseParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_RequireString(parser, "false")) {
+ result = parcJSONValue_CreateFromBoolean(false);
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_NullParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_RequireString(parser, "null")) {
+ result = parcJSONValue_CreateFromNULL();
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_TrueParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_RequireString(parser, "true")) {
+ result = parcJSONValue_CreateFromBoolean(true);
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_StringParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+ PARCBuffer *string = parcJSONParser_ParseString(parser);
+
+ if (string != NULL) {
+ result = parcJSONValue_CreateFromString(string);
+ parcBuffer_Release(&string);
+ }
+
+ return result;
+}
+
+static int
+_digittoint(char digit)
+{
+ return digit - '0';
+}
+
+/*
+ * Parse the whole number portion of a number.
+ *
+ * 0
+ * [1-9][0-9]*
+ */
+static bool
+_parseWholeNumber(PARCJSONParser *parser, int64_t *value)
+{
+ bool result = false;
+ int sign = 1;
+
+ char nextCharacter;
+
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == '0') {
+ *value = 0;
+ result = true;
+ } else if (isdigit(nextCharacter)) {
+ *value = _digittoint(nextCharacter);
+ while (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (!isdigit(nextCharacter)) {
+ parcJSONParser_Advance(parser, -1);
+ break;
+ }
+ *value = *value * 10 + _digittoint(nextCharacter);
+ }
+ *value = *value * sign;
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+static bool
+_parseFractionNumber(PARCJSONParser *parser, int64_t *value, int *log10)
+{
+ bool result = false;
+
+ if (parcJSONParser_Remaining(parser) > 0) {
+ *value = 0;
+ *log10 = 0;
+ char nextCharacter;
+ while (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (!isdigit(nextCharacter)) {
+ parcJSONParser_Advance(parser, -1);
+ break;
+ }
+ *value = *value * 10 + _digittoint(nextCharacter);
+ *log10 = *log10 + 1;
+ }
+
+ result = true;
+ }
+
+ return result;
+}
+
+/**
+ * Parse an optional fractional part of a number.
+ *
+ * If the parser is positioned at a '.' character, then parse a fraction comprised of numbers.
+ * Otherwise, if the parser is positioned at a 'e' ',' ']' or '}' then there is no fraction, but not an error.
+ * If the parser is positioned at any other character, then it is a syntax error.
+ *
+ * @param [in] parser A pointer to a PARCJSONParser instance.
+ * @param [out] value A pointer to an integer accumulating the fraction as a whole number.
+ * @param [out] log10 A pointer to an integer accumulating the base 10 logarithm of the fraction (as a positive integer).
+ *
+ * @return true If there was no syntax error.
+ * @return false If there was a syntax error.
+ */
+static bool
+_parseOptionalFraction(PARCJSONParser *parser, int64_t *value, int *log10)
+{
+ bool result = true;
+
+ // The parser is either looking at an '.' which signals the start of a fractional part,
+ // or a 'e' ',' ']' or '}' which signals a missing fractional part.
+ // Any other character would be the beginning of a syntax error.
+
+ char nextCharacter;
+
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == '.') {
+ if (_parseFractionNumber(parser, value, log10) == false) {
+ result = false;
+ }
+ } else if (nextCharacter == 'e' || nextCharacter == ',' || nextCharacter == ']' || nextCharacter == '}') {
+ parcJSONParser_Advance(parser, -1);
+ result = true;
+ } else {
+ parcJSONParser_Advance(parser, -1);
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Parse and compute the base 10 value of a a sequence of digits from 0 to 9, inclusive.
+ *
+ * @param [in] parser A pointer to a PARCJSONParser instance.
+ * @param [out] value A pointer to a value that will receive the base 10 value.
+ *
+ * @return true If there were parsable digits.
+ */
+static bool
+_parseDigits09(PARCJSONParser *parser, int64_t *value)
+{
+ bool result = false;
+
+ *value = 0;
+ char nextDigit;
+ while (parcJSONParser_Next(parser, &nextDigit)) {
+ *value = *value * 10 + _digittoint(nextDigit);
+ result = true;
+ }
+
+ return result;
+}
+
+static bool
+_parseExponentNumber(PARCJSONParser *parser, int64_t *value)
+{
+ bool result = false;
+ int sign = 1;
+
+ char nextCharacter;
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == '-') {
+ sign = -1;
+ if (_parseDigits09(parser, value)) {
+ result = true;
+ }
+ *value = *value * sign;
+ } else if (nextCharacter == '+') {
+ sign = 1;
+ if (_parseDigits09(parser, value)) {
+ result = true;
+ }
+ *value = *value * sign;
+ } else if (isdigit(nextCharacter)) {
+ parcJSONParser_Advance(parser, -1);
+ if (_parseDigits09(parser, value)) {
+ result = true;
+ }
+ *value = *value * sign;
+ } else {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+static bool
+_parseOptionalExponent(PARCJSONParser *parser, int64_t *value)
+{
+ // The parser is either looking at a 'e' or 'E' ',' ']' or '}'
+ bool result = true;
+
+ char nextCharacter;
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == 'e' || nextCharacter == 'E') {
+ if (_parseExponentNumber(parser, value) == false) {
+ result = false;
+ }
+ } else if (nextCharacter == ',' || nextCharacter == ']' || nextCharacter == '}') {
+ parcJSONParser_Advance(parser, -1);
+ result = true;
+ } else {
+ parcJSONParser_Advance(parser, -1);
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+static __attribute__ ((noinline)) PARCJSONValue *
+_parcJSONValue_CreateNumber(int sign, int64_t whole, int64_t fraction, int64_t fractionLog10, int64_t exponent)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Number);
+ if (result != NULL) {
+ result->value.number.sign = sign;
+ result->value.number.whole = whole;
+ result->value.number.fraction = fraction;
+ result->value.number.fractionLog10 = fractionLog10;
+ result->value.number.exponent = exponent;
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_NumberParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+ int sign = 1;
+ int64_t whole = 0;
+ int64_t fraction = 0;
+ int64_t exponent = 0;
+ int fractionLog10 = 0;
+
+ if (_parseSign(parser, &sign)) {
+ if (_parseWholeNumber(parser, &whole)) {
+ if (_parseOptionalFraction(parser, &fraction, &fractionLog10)) {
+ if (_parseOptionalExponent(parser, &exponent)) {
+ result = _parcJSONValue_CreateNumber(sign, whole, fraction, fractionLog10, exponent);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_ArrayParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_NextChar(parser) == '[') {
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ while (parcJSONParser_Remaining(parser)) {
+ char peek = parcJSONParser_PeekNextChar(parser);
+ if (peek == ',') {
+ parcJSONParser_NextChar(parser);
+ } else if (peek == ']') {
+ parcJSONParser_NextChar(parser); // absorb the ']' character
+ result = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+ break;
+ } else {
+ PARCJSONValue *value = NULL;
+
+ if (peek == 'n') {
+ value = _parcJSONValue_NullParser(parser);
+ } else if (peek == 't') {
+ value = _parcJSONValue_TrueParser(parser);
+ } else if (peek == 'f') {
+ value = _parcJSONValue_FalseParser(parser);
+ } else if (peek == '"') {
+ value = _parcJSONValue_StringParser(parser);
+ } else if (peek == '{') {
+ value = parcJSONValue_ObjectParser(parser);
+ } else if (peek == '[') {
+ value = _parcJSONValue_ArrayParser(parser);
+ } else {
+ value = _parcJSONValue_NumberParser(parser);
+ }
+
+ if (value != NULL) {
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ } else {
+ parcJSONArray_Release(&array);
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_displayBoolean(const PARCJSONValue *value, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, ".value=%s", value->value.boolean == true ? "true" : "false");
+}
+
+static void
+_displayNumber(const PARCJSONValue *value, int indentation)
+{
+ if (value->value.number.internalDoubleRepresentation) {
+ parcDisplayIndented_PrintLine(indentation, ".value=%Lf", value->value.number.internalDoubleValue);
+ } else {
+ parcDisplayIndented_PrintLine(indentation,
+ ".value.number={ sign=%d whole=%lld fractionLog10=%d fraction=%lld exponent=%lld",
+ value->value.number.sign,
+ value->value.number.whole,
+ (int) value->value.number.fractionLog10,
+ value->value.number.fraction,
+ value->value.number.exponent);
+ }
+}
+
+void
+parcJSONValue_AssertValid(const PARCJSONValue *value)
+{
+ assertNotNull(value, "PARCJSONValue cannot be NULL.");
+}
+
+bool
+parcJSONValue_IsValid(const PARCJSONValue *value)
+{
+ bool result = true;
+
+ if (value == NULL) {
+ result = false;
+ }
+
+ return result;
+}
+
+bool
+parcJSONValue_IsNull(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Null);
+}
+
+bool
+parcJSONValue_IsBoolean(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Boolean);
+}
+
+bool
+parcJSONValue_IsNumber(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Number);
+}
+
+bool
+parcJSONValue_IsJSON(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_JSON);
+}
+
+bool
+parcJSONValue_IsString(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_String);
+}
+
+bool
+parcJSONValue_IsArray(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Array);
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromNULL(void)
+{
+ // Strictly speaking, this could just be a singleton, rather than allocated every time.
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Null);
+
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromBoolean(bool value)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Boolean);
+ if (result != NULL) {
+ result->value.boolean = value;
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromFloat(long double value)
+{
+ PARCJSONValue *result = _parcJSONValue_CreateNumber(0, 0, 0, 0, 0);
+ result->value.number.internalDoubleRepresentation = true;
+ result->value.number.internalDoubleValue = value;
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromInteger(int64_t value)
+{
+ PARCJSONValue *result = _parcJSONValue_CreateNumber(1, value, 0, 0, 0);
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromString(PARCBuffer *value)
+{
+ parcBuffer_OptionalAssertValid(value);
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_String);
+ if (result != NULL) {
+ result->value.string = parcBuffer_Acquire(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromCString(const char *value)
+{
+ assertNotNull(value, "String cannot be NULL.");
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_String);
+ if (result != NULL) {
+ result->value.string = parcBuffer_AllocateCString(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromJSONArray(PARCJSONArray *value)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Array);
+ if (result != NULL) {
+ result->value.array = parcJSONArray_Acquire(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromJSON(PARCJSON *value)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_JSON);
+ if (result != NULL) {
+ result->value.object = parcJSON_Acquire(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromTimeval(const struct timeval *timeval)
+{
+ PARCJSON *jsonTimeval = parcJSON_Create();
+ parcJSON_AddInteger(jsonTimeval, "seconds", timeval->tv_sec);
+ parcJSON_AddInteger(jsonTimeval, "micros", timeval->tv_usec);
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_JSON);
+ if (result != NULL) {
+ result->value.object = jsonTimeval;
+ }
+
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromTimespec(const struct timespec *timespec)
+{
+ PARCJSON *jsonTimespec = parcJSON_Create();
+ parcJSON_AddInteger(jsonTimespec, "seconds", timespec->tv_sec);
+ parcJSON_AddInteger(jsonTimespec, "nanos", timespec->tv_nsec);
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_JSON);
+ if (result != NULL) {
+ result->value.object = jsonTimespec;
+ }
+
+ return result;
+}
+
+void
+parcJSONValue_Display(const PARCJSONValue *value, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSONValue@%p {", value);
+ if (value != NULL) {
+ parcDisplayIndented_PrintLine(indentation + 1, ".type=%d", value->type);
+
+ switch (value->type) {
+ case PARCJSONValueType_Boolean:
+ _displayBoolean(value, indentation + 1);
+ break;
+ case PARCJSONValueType_String:
+ parcBuffer_Display(value->value.string, indentation + 1);
+ break;
+ case PARCJSONValueType_Number:
+ _displayNumber(value, indentation + 1);
+ break;
+ case PARCJSONValueType_Array:
+ parcJSONArray_Display(value->value.array, indentation + 1);
+ break;
+ case PARCJSONValueType_JSON:
+ parcJSON_Display(value->value.object, indentation + 1);
+ break;
+ case PARCJSONValueType_Null:
+ parcDisplayIndented_PrintLine(indentation + 1, ".value=null");
+ break;
+ default:
+ trapIllegalValue(value->type, "Unknown PARCJSONValue type %d", value->type);
+ }
+ }
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+parcObject_ImplementAcquire(parcJSONValue, PARCJSONValue);
+
+parcObject_ImplementRelease(parcJSONValue, PARCJSONValue);
+
+static bool
+_equalsNumber(const PARCJSONValue *valueA, const PARCJSONValue *valueB)
+{
+ bool result = false;
+
+ if (valueA->value.number.internalDoubleRepresentation) {
+ if (valueB->value.number.internalDoubleRepresentation) {
+ if (valueA->value.number.internalDoubleValue == valueB->value.number.internalDoubleValue) {
+ result = true;
+ }
+ }
+ } else {
+ if (valueA->value.number.sign == valueB->value.number.sign) {
+ if (valueA->value.number.whole == valueB->value.number.whole) {
+ if (valueA->value.number.fraction == valueB->value.number.fraction) {
+ if (valueA->value.number.exponent == valueB->value.number.exponent) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcJSONValue_Equals(const PARCJSONValue *objA, const PARCJSONValue *objB)
+{
+ bool result = false;
+
+ if (objA == NULL || objB == NULL) {
+ result = (objA == objB);
+ } else {
+ if (objA->type == objB->type) {
+ switch (objA->type) {
+ case PARCJSONValueType_Boolean:
+ result = objA->value.boolean == objB->value.boolean;
+ break;
+ case PARCJSONValueType_String:
+ result = parcBuffer_Equals(objA->value.string, objB->value.string);
+ break;
+ case PARCJSONValueType_Number:
+ result = _equalsNumber(objA, objB);
+ break;
+ case PARCJSONValueType_Array:
+ result = parcJSONArray_Equals(objA->value.array, objB->value.array);
+ break;
+ case PARCJSONValueType_JSON:
+ result = parcJSON_Equals(objA->value.object, objB->value.object);
+ break;
+ case PARCJSONValueType_Null:
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCJSONArray *
+parcJSONValue_GetArray(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsArray(value), "Expected type to be array, actual type %d", value->type);
+
+ return value->value.array;
+}
+
+bool
+parcJSONValue_GetBoolean(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsBoolean(value), "Expected type to be boolean, actual type %d", value->type);
+
+ return value->value.boolean;
+}
+
+static long double
+_parcJSONValue_GetNumber(const PARCJSONValue *value)
+{
+ long double fraction = value->value.number.fraction / powl(10.0, value->value.number.fractionLog10);
+ long double number = (long double) value->value.number.sign * ((long double) value->value.number.whole + fraction);
+
+ long double result = number * powl(10.0, (long double) value->value.number.exponent);
+
+ return result;
+}
+
+long double
+parcJSONValue_GetFloat(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ long double result = 0;
+
+ if (value->value.number.internalDoubleRepresentation) {
+ result = value->value.number.internalDoubleValue;
+ } else {
+ result = _parcJSONValue_GetNumber(value);
+ }
+
+ return result;
+}
+
+int64_t
+parcJSONValue_GetInteger(const PARCJSONValue *value)
+{
+ int64_t result = llrint(_parcJSONValue_GetNumber(value));
+ return result;
+}
+
+PARCBuffer *
+parcJSONValue_GetString(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsString(value), "Expected type to be string, actual type %d", value->type);
+
+ return value->value.string;
+}
+
+PARCJSON *
+parcJSONValue_GetJSON(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsJSON(value), "Expected type to be string, actual type %d", value->type);
+
+ return value->value.object;
+}
+
+struct timeval *
+parcJSONValue_GetTimeval(const PARCJSONValue *jsonTimeval, struct timeval *timeval)
+{
+ assertNotNull(jsonTimeval, "Parameter jsonTimeval must be a non-null PARCJSON pointer.");
+
+ PARCJSON *json = parcJSONValue_GetJSON(jsonTimeval);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, "seconds");
+ timeval->tv_sec = parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(json, "micros");
+ timeval->tv_usec = (int) parcJSONValue_GetInteger(value);
+
+ return timeval;
+}
+
+struct timespec *
+parcJSONValue_GetTimespec(const PARCJSONValue *jsonTimespec, struct timespec *timespec)
+{
+ assertNotNull(jsonTimespec, "Parameter jsonTimeval must be a non-null PARCJSON pointer.");
+
+ PARCJSON *json = parcJSONValue_GetJSON(jsonTimespec);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, "seconds");
+ timespec->tv_sec = parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(json, "nanos");
+ timespec->tv_nsec = (int) parcJSONValue_GetInteger(value);
+
+ return timespec;
+}
+
+static PARCBufferComposer *
+_buildStringNumber(const PARCJSONValue *value, PARCBufferComposer *string)
+{
+ if (value->value.number.internalDoubleRepresentation) {
+ parcBufferComposer_Format(string, "%Lf", value->value.number.internalDoubleValue);
+ } else {
+ parcBufferComposer_Format(string, "%s%" PRId64,
+ value->value.number.sign == -1 ? "-" : "",
+ value->value.number.whole);
+ if (value->value.number.fraction > 0) {
+ parcBufferComposer_Format(string, ".%0*" PRId64,
+ (int) value->value.number.fractionLog10,
+ value->value.number.fraction);
+ }
+
+ if (value->value.number.exponent != 0) {
+ parcBufferComposer_Format(string, "e%" PRId64,
+ value->value.number.exponent);
+ }
+ }
+ return string;
+}
+
+static PARCBufferComposer *
+_buildStringString(const PARCJSONValue *value, PARCBufferComposer *composer, bool compact)
+{
+ parcBufferComposer_PutChar(composer, '"');
+
+ while (parcBuffer_Remaining(value->value.string)) {
+ uint8_t c = parcBuffer_GetUint8(value->value.string);
+ if (c == '"') {
+ parcBufferComposer_PutString(composer, "\\\"");
+ } else if (c == '\b') {
+ parcBufferComposer_PutString(composer, "\\b");
+ } else if (c == '\f') {
+ parcBufferComposer_PutString(composer, "\\f");
+ } else if (c == '\n') {
+ parcBufferComposer_PutString(composer, "\\n");
+ } else if (c == '\r') {
+ parcBufferComposer_PutString(composer, "\\r");
+ } else if (c == '\t') {
+ parcBufferComposer_PutString(composer, "\\t");
+ } else if ((c == '/') && !compact) {
+ parcBufferComposer_PutString(composer, "\\/");
+ } else if (c == '\\') {
+ parcBufferComposer_PutString(composer, "\\\\");
+ } else {
+ parcBufferComposer_PutChar(composer, c);
+ }
+ }
+
+ parcBuffer_Rewind(value->value.string);
+ parcBufferComposer_PutChar(composer, '"');
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcJSONValue_BuildString(const PARCJSONValue *value, PARCBufferComposer *composer, bool compact)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ if (value->type == PARCJSONValueType_Boolean) {
+ parcBufferComposer_PutString(composer, value->value.boolean ? "true" : "false");
+ } else if (value->type == PARCJSONValueType_String) {
+ _buildStringString(value, composer, compact);
+ } else if (value->type == PARCJSONValueType_Number) {
+ _buildStringNumber(value, composer);
+ } else if (value->type == PARCJSONValueType_Array) {
+ parcJSONArray_BuildString(value->value.array, composer, compact);
+ } else if (value->type == PARCJSONValueType_JSON) {
+ parcJSON_BuildString(value->value.object, composer, compact);
+ } else if (value->type == PARCJSONValueType_Null) {
+ parcBufferComposer_PutString(composer, "null");
+ } else {
+ trapIllegalValue(value->type, "Unknown value type: %d", value->type);
+ }
+
+ return composer;
+}
+
+static char *
+_parcJSONValue_ToString(const PARCJSONValue *value, bool compact)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONValue_BuildString(value, composer, compact);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+char *
+parcJSONValue_ToString(const PARCJSONValue *value)
+{
+ return _parcJSONValue_ToString(value, false);
+}
+
+char *
+parcJSONValue_ToCompactString(const PARCJSONValue *value)
+{
+ return _parcJSONValue_ToString(value, true);
+}
+
+PARCJSONValue *
+parcJSONValue_Parser(PARCJSONParser *parser)
+{
+ char nextCharacter = parcJSONParser_PeekNextChar(parser);
+ switch (nextCharacter) {
+ case ',':
+ break;
+
+ case ']':
+ return NULL;
+
+ case 'n':
+ return _parcJSONValue_NullParser(parser);
+
+ case 't':
+ return _parcJSONValue_TrueParser(parser);
+
+ case 'f':
+ return _parcJSONValue_FalseParser(parser);
+
+ case '"':
+ return _parcJSONValue_StringParser(parser);
+
+ case '[':
+ return _parcJSONValue_ArrayParser(parser);
+
+ case '{':
+ return parcJSONValue_ObjectParser(parser);
+
+ default:
+ return _parcJSONValue_NumberParser(parser);
+ }
+
+ return NULL;
+}
+
+PARCJSONValue *
+parcJSONValue_ObjectParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ // absorb the (required) '{' character.
+ if (parcJSONParser_NextChar(parser) == '{') {
+ PARCJSON *json = parcJSON_Create();
+
+ while (parcJSONParser_Remaining(parser)) {
+ char c = parcJSONParser_PeekNextChar(parser);
+ if (c == '}') {
+ // Absorb the '}' and terminate.
+ parcJSONParser_NextChar(parser);
+ result = parcJSONValue_CreateFromJSON(json);
+ break;
+ } else if (c == ',') {
+ // absorb the ',' character and continue
+ parcJSONParser_NextChar(parser);
+ } else if (c == '"') {
+ PARCJSONPair *pair = parcJSONPair_Parser(parser);
+ if (pair == NULL) {
+ break;
+ }
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ } else {
+ break;
+ }
+ }
+ parcJSON_Release(&json);
+ }
+
+ return result;
+}
+
diff --git a/libparc/parc/algol/parc_JSONValue.h b/libparc/parc/algol/parc_JSONValue.h
new file mode 100755
index 00000000..300a1c0c
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONValue.h
@@ -0,0 +1,938 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_JSON.h
+ * @ingroup inputoutput
+ * @brief A JSON value. One of a Boolean, String, Number, JSON Array, JSON Object, or Null.
+ *
+ */
+#ifndef libparc_parc_JSONValue_h
+#define libparc_parc_JSONValue_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_json_value;
+typedef struct parc_json_value PARCJSONValue;
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_JSONParser.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONArray.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_List.h>
+
+/**
+ * @def parcJSONValue_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to nullify validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcJSONValue_OptionalAssertValid(_instance_)
+#else
+# define parcJSONValue_OptionalAssertValid(_instance_) parcJSONValue_AssertValid(_instance_)
+#endif
+
+/**
+ * Print a human readable representation of the given `PARCJSONValue`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] value A pointer to the instance of `PARCJSONValue` to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *instance = parcJSONValue_CreateFromNull();
+ *
+ * parcJSONValue_Display(instance, 0);
+ *
+ * parcJSONValue_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcJSONValue_Display(const PARCJSONValue *value, int indentation);
+
+/**
+ * Determine if @p value is a JSON Null.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Null.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ *
+ * if (parcJSONValue_IsNull(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromNULL
+ */
+bool parcJSONValue_IsNull(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Boolean.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Boolean.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true);
+ *
+ * if (parcJSONValue_IsBoolean(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromNULL
+ */
+bool parcJSONValue_IsBoolean(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Number.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.14);
+ *
+ * if (parcJSONValue_IsNumber(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_GetInteger
+ * @see parcJSONValue_GetFloat
+ */
+bool parcJSONValue_IsNumber(const PARCJSONValue *value);
+
+/**
+ * Determine if the pointer to a `PARCJSONValue` is valid.
+ *
+ * @param [in] value A pointer to a `PARCJSONValue`.
+ *
+ * @return true The `PARCJSONValue` is valid.
+ * @return false The `PARCJSONValue` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create());
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ * parcJSON_Release(&json);
+ *
+ * if (parcJSONValue_IsValid(value)) {
+ * printf("Valid!\n");
+ * } else {
+ * printf("Invalid!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+bool parcJSONValue_IsValid(const PARCJSONValue *value);
+
+/**
+ * Assert that an instance of `PARCJSONValue` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue()}
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] value A pointer to a `PARCJSONValue` instance.
+ */
+void parcJSONValue_AssertValid(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Object.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Object.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create());
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ * parcJSON_Release(&json);
+ *
+ * if (parcJSONValue_IsObject(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromJSON
+ */
+bool parcJSONValue_IsJSON(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON String.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON String.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *string = parcBuffer_Wrap("Hello", 0, 5);
+ * PARCJSONValue *value = parcJSONValue_CreateFromString(string);
+ * parcBuffer_Release(&string);
+ *
+ * if (parcJSONValue_IsString(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromString
+ */
+bool parcJSONValue_IsString(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Array.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSONArray(array);
+ * parcJSONArray_Release(&array);
+ *
+ * if (parcJSONValue_IsArray(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromJSONArray
+ */
+bool parcJSONValue_IsArray(const PARCJSONValue *value);
+
+/**
+ * Get the value of the given `PARCJSONValue` as a {@link PARCJSONArray} instance.
+ *
+ * The value must be a JSON Array.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return A pointer to a `PARCJSONArray` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" [ ]");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * PARCJSONArray *array = parcJSONValue_GetArray(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsArray
+ */
+PARCJSONArray *parcJSONValue_GetArray(const PARCJSONValue *value);
+
+/**
+ * Get the given value is a `bool`
+ *
+ * The value must be a JSON Array of the type {@link PARCJSONValueType_Boolean}
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return A `bool` representation.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" true");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * bool result = parcJSONValue_GetBoolean(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see {link parcJSONValue_IsBoolean}
+ */
+bool parcJSONValue_GetBoolean(const PARCJSONValue *value);
+
+/**
+ * Get the JSON float value is a `long double`
+ *
+ *
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return The value as a C double.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" 3.1415");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * long double result = parcJSONValue_GetFloat(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsNumber
+ */
+long double parcJSONValue_GetFloat(const PARCJSONValue *value);
+
+/**
+ * Get the given value as an integer.
+ *
+ * The value must be a JSON Number value.
+ * The result must be expressible in a 64-bit integer (`int64_t`).
+ * Overflow is not detected.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return The value as a C `int64_t`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" 31415");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * int64_t result = parcJSONValue_GetInteger(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsNumber
+ */
+int64_t parcJSONValue_GetInteger(const PARCJSONValue *value);
+
+/**
+ * Get the given value is a null-terminated C string.
+ *
+ * The value must be a JSON Array of the type {@link PARCJSONValueType_String}
+ *
+ * A new reference to the return value is not created.
+ * The caller must create a new reference, if it retains a reference to the buffer.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return A pointer to a {@link PARCBuffer} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" \"a string\"");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * PARCBuffer *result = parcJSONValue_GetString(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsString
+ */
+PARCBuffer *parcJSONValue_GetString(const PARCJSONValue *value);
+
+/**
+ * Get the value of a JSON object.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return The value as a pointer to a {@link PARCJSON} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : \"a string\" }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * PARCJSON *result = parcJSONValue_GetJSON(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsJSON
+ */
+PARCJSON *parcJSONValue_GetJSON(const PARCJSONValue *value);
+
+/**
+ * Convenience function to fill a timeval struct from a PARCJSONValue.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ * @param [out] timeval A pre-allocated timeval struct to fill.
+ *
+ * @return A pointer to the filled timeval struct.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"seconds\" : 10, \"micros\" : 0 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcBuffer_Release(&buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ * parcJSONParser_Release(&parser);
+ *
+ * struct timeval timeval;
+ * parcJSONValue_GetTimeval(value, &timeval);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ */
+struct timeval *parcJSONValue_GetTimeval(const PARCJSONValue *value, struct timeval *timeval);
+
+/**
+ * Convenience function to fill a timespec struct from a PARCJSONValue.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ * @param [out] timespec A pre-allocated timespec struct to fill.
+ *
+ * @return A pointer to the filled timespec struct.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"seconds\" : 10, \"nanos\" : 0 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcBuffer_Release(&buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ * parcJSONParser_Release(&parser);
+ *
+ * struct timespec timespec;
+ * parcJSONValue_GetTimespec(value, &timespec);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ */
+struct timespec *parcJSONValue_GetTimespec(const PARCJSONValue *value, struct timespec *timespec);
+
+/**
+ * Create a NULL JSON value.
+ *
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ */
+PARCJSONValue *parcJSONValue_CreateFromNULL(void);
+
+/**
+ * Create a boolean value.
+ *
+ * @param [in] value Either `true` or `false.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromBoolean(bool value);
+
+/**
+ * Create a float value.
+ *
+ * The resulting PARCJSONValue is a number (see {@link parcJSONValue_IsNumber}).
+ *
+ * @param [in] value A `long double` value.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.14);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromFloat(long double value);
+
+/**
+ * Create a JSON integer value.
+ *
+ * The resulting PARCJSONValue is a number (see {@link parcJSONValue_IsNumber} ).
+ *
+ * @param [in] integer An `int64_t` value.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(3);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromInteger(int64_t integer);
+
+/**
+ * Create a string value from the contents of a {@link PARCBuffer}.
+ *
+ * @param [in] string A pointer to a `PARCBuffer` instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *string = parcBuffer_AllocateCString("hello"):
+ * PARCJSONValue *value = parcJSONValue_CreateFromString(string);
+ *
+ * parcJSONValue_Release(&value);
+ * parcBuffer_Release(&string);
+ * }
+ * @endcode
+ * @see parcJSONValue_CreateFromCString
+ */
+PARCJSONValue *parcJSONValue_CreateFromString(PARCBuffer *string);
+
+/**
+ * Create a string value from a null-terminated C string.
+ *
+ * @param [in] string A pointer to a {@link PARCBuffer} instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromCString("hello");
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ * @see parcJSONValue_CreateFromString
+ */
+PARCJSONValue *parcJSONValue_CreateFromCString(const char *string);
+
+/**
+ * Create a JSON Array value.
+ *
+ * @param [in] array A pointer to a {@link PARCJSONArray} instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ * PARCJSONValue *value = parcJSONValue_CreateFromPARCArray(array);
+ *
+ * PARCJSONArray_Release(&array);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromJSONArray(PARCJSONArray *array);
+
+/**
+ * Create a JSON Value containing a JSON Object.
+ *
+ * A new reference to the given {@link PARCJSON} instance is acquired.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ *
+ * parcJSON_Release(&json);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromJSON(PARCJSON *json);
+
+/**
+ * A convenience function to create a JSON Value containing a JSON Object representing a timeval.
+ *
+ * A new reference to the given {@link PARCJSON} instance is acquired. The json keys for the
+ * timespec fields are are "seconds" & "micros".
+ *
+ * @param [in] timeval A pointer to a timeval instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval timeval = { .tv_sec = 1, .tv_usec = 1 };
+ * PARCJSONValue *value = parcJSONValue_CreateFromTimeval(&timeval);
+ *
+ * parcJSON_Release(&json);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromTimeval(const struct timeval *timeval);
+
+/**
+ * A convenience function to create a JSON Value containing a JSON Object representing a timespec.
+ *
+ * A new reference to the given {@link PARCJSON} instance is acquired. The json keys for the
+ * timespec fields are are "seconds" & "nanos".
+ *
+ * @param [in] timeval A pointer to a timespec instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timespec timespec = { .tv_sec = 10, .tv_nsec = 0 };
+ * PARCJSONValue *value = parcJSONValue_CreateFromTimespec(&timespec);
+ *
+ * parcJSON_Release(&json);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromTimespec(const struct timespec *timespec);
+
+/**
+ * Increase the number of references to a `PARCJSONValue`.
+ *
+ * Note that new `PARCJSONValue` is not created,
+ * only that the given `PARCJSONValue` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSONValue_Release}.
+ *
+ * @param [in] value A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *x = parcJSONValue_CreateFromNull();
+ *
+ * PARCJSONValue *x2 = parcJSONValue_Acquire(x);
+ *
+ * parcJSONValue_Release(&x);
+ * parcJSONValue_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_Release
+ */
+PARCJSONValue *parcJSONValue_Acquire(const PARCJSONValue *value);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] valuePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *x = parcJSONValue_CreateFromNull();
+ *
+ * parcJSONValue_Release(&x);
+ * }
+ * @endcode
+ */
+void parcJSONValue_Release(PARCJSONValue **valuePtr);
+
+/**
+ * Determine if two `PARCJSONValue` instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `PARCJSONValue` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSONValue_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcJSONValue_Equals(x, y)` must return true if and only if
+ * `parcJSONValue_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSONValue_Equals(x, y)` returns true and
+ * `parcJSONValue_Equals(y, z)` returns true,
+ * then `parcJSONValue_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcJSONValue_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSONValue_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCJSONValue` instance.
+ * @param [in] y A pointer to a `PARCJSONValue` instance.
+ * @return true if the two `PARCJSONValue` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *x = parcJSONValue_CreateFromBoolean(true);
+ * PARCJSONValue *y = parcJSONValue_CreateFromBoolean(true);
+ *
+ * if (parcJSONValue_Equals(x, y)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcJSONValue_Equals(const PARCJSONValue *x, const PARCJSONValue *y);
+
+/**
+ * Produce a null-terminated string representation of the specified instance of `PARCJSONValue`.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] value A pointer to the `PARCJSONValue` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *instance = parcJSONValue_CreateFromString("Hello World");
+ *
+ * char *string = parcJSONValue_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSONValue_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_BuildString
+ * @see parcJSONValue_Display
+ */
+char *parcJSONValue_ToString(const PARCJSONValue *value);
+
+/**
+ * Produce a null-terminated "compact" (minimal escaping and formatting) string representation
+ * of the specified instance of `PARCJSONValue`.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] value A pointer to the `PARCJSONValue` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *instance = parcJSONValue_CreateFromString("Hello World");
+ *
+ * char *string = parcJSONValue_ToCompactString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSONValue_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_BuildString
+ * @see parcJSONValue_Display
+ */
+char *parcJSONValue_ToCompactString(const PARCJSONValue *value);
+
+/**
+ * Append a representation of the specified instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] value A pointer to a {@link PARCJSONParser} instance.
+ * @param [in,out] composer A pointer to the {@link PARCBufferComposer} instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSONValue_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("JSON Value: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSONValue_BuildString(const PARCJSONValue *value, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Parse an arbitrary JSON value.
+ *
+ * The value may be any valid JSON value, consisting of strings, numbers, objects, arrays, `true`, `false`, or `null`
+ * in their properly encoded string format.
+ *
+ * @param [in] parser A pointer to a {@link PARCJSONParser} instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONValue` instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" 123");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_NumberParser
+ */
+PARCJSONValue *parcJSONValue_Parser(PARCJSONParser *parser);
+
+
+/**
+ * Parse a JSON Object value.
+ *
+ * @param [in] parser A pointer to a {@link PARCJSONParser} instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONValue` instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_ObjectParser(parser);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_ObjectParser(PARCJSONParser *parser);
+#endif // libparc_parc_JSONValue_h
diff --git a/libparc/parc/algol/parc_KeyValue.c b/libparc/parc/algol/parc_KeyValue.c
new file mode 100755
index 00000000..27b20f35
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyValue.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "parc_KeyValue.h"
+#include "parc_Object.h"
+
+#include <LongBow/runtime.h>
+
+struct parc_key_value {
+ PARCObject *key;
+ PARCObject *value;
+};
+
+static void
+_parcKeyValue_Destroy(PARCKeyValue **keyValuePointer)
+{
+ PARCKeyValue *keyValue = *keyValuePointer;
+ parcObject_Release(&keyValue->key);
+ if (keyValue->value != NULL) {
+ parcObject_Release(&keyValue->value);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCKeyValue, _parcKeyValue_Destroy, parcKeyValue_Copy, NULL, parcKeyValue_Equals,
+ parcKeyValue_Compare, parcKeyValue_HashCode, NULL);
+
+parcObject_ImplementAcquire(parcKeyValue, PARCKeyValue);
+
+parcObject_ImplementRelease(parcKeyValue, PARCKeyValue);
+
+PARCKeyValue *
+parcKeyValue_Create(const PARCObject *key,
+ const PARCObject *value)
+{
+ assertNotNull(key, "Key may not be null in a KeyValue element");
+
+ PARCKeyValue *keyValue = parcObject_CreateInstance(PARCKeyValue);
+ assertNotNull(keyValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCKeyValue));
+
+ keyValue->key = parcObject_Acquire(key);
+ keyValue->value = NULL;
+ if (value != NULL) {
+ keyValue->value = parcObject_Acquire(value);
+ }
+
+ return keyValue;
+}
+
+PARCKeyValue *
+parcKeyValue_Copy(const PARCKeyValue *source)
+{
+ PARCKeyValue *newKV = parcObject_CreateInstance(PARCKeyValue);
+ newKV->key = parcObject_Copy(source->key);
+ newKV->value = NULL;
+ if (source->value != NULL) {
+ newKV->value = parcObject_Copy(source->value);
+ }
+
+ return newKV;
+}
+
+void
+parcKeyValue_SetValue(PARCKeyValue *keyValue, PARCObject *value)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ PARCObject *oldValue = keyValue->value;
+ if (value != NULL) {
+ keyValue->value = parcObject_Acquire(value);
+ } else {
+ keyValue->value = NULL;
+ }
+ if (oldValue != NULL) {
+ parcObject_Release(&oldValue);
+ }
+}
+
+void
+parcKeyValue_SetKey(PARCKeyValue *keyValue, PARCObject *key)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ PARCObject *oldKey = keyValue->key;
+ keyValue->key = parcObject_Acquire(key);
+ parcObject_Release(&oldKey);
+}
+
+PARCObject *
+parcKeyValue_GetValue(PARCKeyValue *keyValue)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ return keyValue->value;
+}
+
+PARCObject *
+parcKeyValue_GetKey(PARCKeyValue *keyValue)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ return keyValue->key;
+}
+
+bool
+parcKeyValue_Equals(const PARCKeyValue *a, const PARCKeyValue *b)
+{
+ bool result = parcObject_Equals(a->key, b->key);
+ if ((a->value == NULL) || (b->value == NULL)) {
+ result &= (a->value == b->value); // Only true if both are NULL
+ } else {
+ result &= parcObject_Equals(a->value, b->value);
+ }
+ return result;
+}
+
+int
+parcKeyValue_Compare(const PARCKeyValue *a, const PARCKeyValue *b)
+{
+ if (a == NULL && b == NULL) {
+ return 0;
+ }
+ if (a != NULL && b == NULL) {
+ return 1;
+ }
+ if (a == NULL && b != NULL) {
+ return -1;
+ } else {
+ return parcObject_Compare(a->key, b->key);
+ }
+}
+
+PARCHashCode
+parcKeyValue_HashCode(const PARCKeyValue *keyValue)
+{
+ return parcObject_HashCode(keyValue->key);
+}
+
+bool
+parcKeyValue_EqualKeys(const PARCKeyValue *a, const PARCKeyValue *b)
+{
+ return parcObject_Equals(a->key, b->key);
+}
diff --git a/libparc/parc/algol/parc_KeyValue.h b/libparc/parc/algol/parc_KeyValue.h
new file mode 100755
index 00000000..a4bc3915
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyValue.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_KeyValue.h
+ * @ingroup datastructures
+ * @brief A key and value tuple.
+ *
+ * The `PARCKeyValue` is a simple key-value tuple.
+ *
+ */
+#ifndef libparc_parc_KeyValue_h
+#define libparc_parc_KeyValue_h
+
+#include "parc_Object.h"
+
+struct parc_key_value;
+
+/**
+ * @typedef `PARCKeyValue`
+ * @brief A `PARCKeyValue` is a tuple consisting of a key and a value
+ */
+typedef struct parc_key_value PARCKeyValue;
+
+/**
+ * Create a `PARCKeyValue` Element. The key and value must be PARCObjects.
+ *
+ * Neither the data nor the key will be copied, but referenced.
+ * The key may not be `NULL`.
+ *
+ * @param [in] key A pointer to the key data
+ * @param [in] value A pointer to the value data
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcKeyValue_Create(const PARCObject *key,
+ const PARCObject *value);
+
+/**
+ * Create a copy of a `PARCKeyValue` Element.
+ *
+ * The source PARCKeyValue may not be `NULL`.
+ *
+ * @param [in] keyValue Source PARCKeyValue element
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKeyValue *keyValueCopy = parcKeyValue_Copy(sourcKeyValue);
+ * ...
+ * parcKeyValue_Release(&keyValueCopy);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcKeyValue_Copy(const PARCKeyValue *keyValue);
+
+/**
+ * Acquire a reference to a `PARCKeyValue` Element.
+ *
+ * The source PARCKeyValue may not be `NULL`.
+ *
+ * @param [in] keyValue Source PARCKeyValue element
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKeyValue *keyValue = parcKeyValue_Acquire(sourcKeyValue);
+ * ...
+ * parcKeyValue_Release(&keyValue);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcKeyValue_Acquire(const PARCKeyValue *keyValue);
+
+/**
+ * Release a `PARCKeyValue`.
+ *
+ * Releases a reference to a PARCKeyValue element, if it is the last reference then the
+ * contained key & value objects are released and the elements memory is freed.
+ *
+ * @param [in,out] keyValuePointer A pointer to the pointer to the `PARCKeyValue` to be released
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+void parcKeyValue_Release(PARCKeyValue **keyValuePointer);
+
+/**
+ * Set the value for a `PARCKeyValue`.
+ * The previous value will be released.
+ *
+ * @param [in,out] keyValue A pointer to the keyValue
+ * @param [in] value A pointer to the new value
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_SetKey(kv, newKey);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+void parcKeyValue_SetValue(PARCKeyValue *keyValue, PARCObject *value);
+
+/**
+ * Set the key for a `PARCKeyValue`.
+ * The previous key will be released.
+ *
+ * @param [in,out] keyValue A pointer to the `PARCKeyValue`
+ * @param [in] key A pointer to the new key
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_SetValue(kv, newValue);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+void parcKeyValue_SetKey(PARCKeyValue *keyValue, PARCObject *key);
+
+/**
+ * Get the value pointer for the `PARCKeyValue`. No extra reference is created.
+ *
+ * @param [in] keyValue A pointer to the `PARCKeyValue`
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * PARCObject *value = parcKeyValue_GetValue(kv);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+PARCObject *parcKeyValue_GetValue(PARCKeyValue *keyValue);
+
+/**
+ * Get the key pointer for the `PARCKeyValue`. No extra reference is created.
+ *
+ * @param [in] keyValue A pointer to the `PARCKeyValue`
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * PARCObject *key = parcKeyValue_GetKey(kv);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+PARCObject *parcKeyValue_GetKey(PARCKeyValue *keyValue);
+
+/**
+ * Check for Key equality. Return true if equal.
+ *
+ * @param [in] keyValue1 A pointer to the first `PARCKeyValue`
+ * @param [in] keyValue2 A pointer to the second `PARCKeyValue`
+ * @return true if the keyValues have the same key
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv1 = parcKeyValue_Create(key1, value);
+ * PARCKeyValue *kv2 = parcKeyValue_Create(key2, value);
+ * ...
+ * if (parcKeyValue_EqualKeys(kv1, kv2)) {
+ * ...
+ * }
+ * ...
+ * parcKeyValue_Release(&kv1);
+ * parcKeyValue_Release(&kv2);
+ * @endcode
+ */
+bool parcKeyValue_EqualKeys(const PARCKeyValue *keyValue1, const PARCKeyValue *keyValue2);
+
+/**
+ * Check for element equality. Return true if both key & value are equal.
+ *
+ * @param [in] keyValue1 A pointer to the first `PARCKeyValue`
+ * @param [in] keyValue2 A pointer to the second `PARCKeyValue`
+ * @return true if the keys & values both have the same value
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv1 = parcKeyValue_Create(key1, value);
+ * PARCKeyValue *kv2 = parcKeyValue_Create(key2, value);
+ * ...
+ * if (parcKeyValue_Equals(kv1, kv2)) {
+ * ...
+ * }
+ * ...
+ * parcKeyValue_Release(&kv1);
+ * parcKeyValue_Release(&kv2);
+ * @endcode
+ */
+bool parcKeyValue_Equals(const PARCKeyValue *keyValue1, const PARCKeyValue *keyValue2);
+
+/**
+ * Compare PARCKeyValue elements. Return an int result based on key compare only.
+ *
+ * @param [in] keyValue1 A pointer to the first `PARCKeyValue`
+ * @param [in] keyValue2 A pointer to the second `PARCKeyValue`
+ * @return parcObject_Compare(keyValue1->key, keyValue2->key)
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv1 = parcKeyValue_Create(key1, value);
+ * PARCKeyValue *kv2 = parcKeyValue_Create(key2, value);
+ * ...
+ * if (parcKeyValue_Compare(kv1, kv2) > 0) {
+ * ...
+ * }
+ * ...
+ * parcKeyValue_Release(&kv1);
+ * parcKeyValue_Release(&kv2);
+ * @endcode
+ */
+int parcKeyValue_Compare(const PARCKeyValue *keyValue1, const PARCKeyValue *keyValue2);
+
+/**
+ * Return the HashCode of the PARCKeyValue key.
+ *
+ * @param [in] keyValue A pointer to the first `PARCKeyValue`
+ * @return parcObject_HashCode(keyValue->key);
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *keyValue = parcKeyValue_Create(key1, value);
+ * ...
+ * PARCHashCode *hashCode = parcKeyValue_HashCode(keyValue);
+ * ...
+ * parcKeyValue_Release(&keyValue);
+ * @endcode
+ */
+PARCHashCode parcKeyValue_HashCode(const PARCKeyValue *keyValue);
+#endif // libparc_parc_KeyValue_h
diff --git a/libparc/parc/algol/parc_KeyedElement.c b/libparc/parc/algol/parc_KeyedElement.c
new file mode 100755
index 00000000..a55de891
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyedElement.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_KeyedElement.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_keyed_element {
+ size_t keylen;
+ void *key;
+ void *element;
+};
+
+PARCKeyedElement *
+parcKeyedElement_Create(void *data, const void *key, size_t keylen)
+{
+ PARCKeyedElement *keyedElement = parcMemory_Allocate(sizeof(PARCKeyedElement));
+ assertNotNull(keyedElement, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCKeyedElement));
+ keyedElement->element = data;
+ keyedElement->key = parcMemory_Allocate(sizeof(PARCKeyedElement));
+ assertNotNull(keyedElement->key, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCKeyedElement));
+ memcpy(keyedElement->key, key, keylen);
+ keyedElement->keylen = keylen;
+ return keyedElement;
+}
+
+void
+parcKeyedElement_Destroy(PARCKeyedElement **keyedElementPointer)
+{
+ parcMemory_Deallocate((void **) &((*keyedElementPointer)->key));
+ parcMemory_Deallocate((void **) keyedElementPointer);
+ *keyedElementPointer = NULL;
+}
+
+void
+parcKeyedElement_SetData(PARCKeyedElement *keyedElement, void *data)
+{
+ keyedElement->element = data;
+}
+
+void *
+parcKeyedElement_GetData(PARCKeyedElement *keyedElement)
+{
+ return keyedElement->element;
+}
+
+void *
+parcKeyedElement_GetKey(PARCKeyedElement *keyedElement)
+{
+ return keyedElement->key;
+}
+
+size_t
+parcKeyedElement_GetKeyLen(PARCKeyedElement *keyedElement)
+{
+ return keyedElement->keylen;
+}
diff --git a/libparc/parc/algol/parc_KeyedElement.h b/libparc/parc/algol/parc_KeyedElement.h
new file mode 100755
index 00000000..e794360f
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyedElement.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_KeyedElement.h
+ * @ingroup datastructures
+ * @brief A Pointer and a Key
+ * The `PARCKeyedElement` is a simple pointer and key tuple.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libparc_parc_KeyedElement_h
+#define libparc_parc_KeyedElement_h
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct parc_keyed_element;
+
+/**
+ * A `PARCKeyedElement` is a tuple consisting of an address and a key+len.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct parc_keyed_element PARCKeyedElement;
+
+/**
+ * Create a `PARCKeyedElement`. Note that the key will be copied (size keylen) while the data will just be
+ * referenced. The key copy will be released when the KeyedElement is destroyed.
+ *
+ * @param [in] data The data we want to associate with a key.
+ * @param [in] key A pointer to the key data (will be copied).
+ * @param [in] keylen The length of the keydata.
+ * @return The new instance of `PARCKeyedElement`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCKeyedElement *parcKeyedElement_Create(void *data, const void *key, size_t keylen);
+
+/**
+ * Destroy a `PARCKeyedElement`.
+ *
+ * If the Free functions were passed to the constructor they will be called if
+ * not NULL. *
+ * @param [in,out] keyedElementPointer A pointer to the pointer to the `PARCKeyedElement` to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcKeyedElement_Destroy(PARCKeyedElement **keyedElementPointer);
+/**
+ * Set the data of a `PARCKeyedElement`.
+ *
+ * @param [in,out] keyedElement The pointer to the `PARCKeyedElement` whose data will be reset to @p data.
+ * @param [in] data The data to put be into @p keyedElement
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcKeyedElement_SetData(PARCKeyedElement *keyedElement, void *data);
+
+/**
+ * Get the data of a `PARCKeyedElement`.
+ *
+ * @param [in] keyedElement The pointer to the `PARCKeyedElement` whose data will be retrieved.
+ * @return A pointer to the retrieved data.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcKeyedElement_GetData(PARCKeyedElement *keyedElement);
+
+/**
+ * Retrieve the key of a `PARCKeyedElement`.
+ *
+ * @param [in] keyedElement A pointer to the `PARCKeyedElement` whose key should be retreieved.
+ *
+ * @return A pointer to the `PARCKeyedElement`'s key.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcKeyedElement_GetKey(PARCKeyedElement *keyedElement);
+
+/**
+ * Return the size of the `PARCKeyedElement`'s key.
+ *
+ * @param [in] keyedElement A pointer to the `PARCKeyedElement` whose key length should be returned.
+ *
+ * @return The length of the retrieved key.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcKeyedElement_GetKeyLen(PARCKeyedElement *keyedElement);
+#endif // libparc_parc_KeyedElement_h
diff --git a/libparc/parc/algol/parc_LinkedList.c b/libparc/parc/algol/parc_LinkedList.c
new file mode 100644
index 00000000..d220e223
--- /dev/null
+++ b/libparc/parc/algol/parc_LinkedList.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+static PARCListInterface *PARCLinkedListAsPARCList = &(PARCListInterface) {
+ .Add = (bool (*)(void *, void *))parcLinkedList_Append,
+ .AddAtIndex = (void (*)(void *, int index, PARCObject *))parcLinkedList_InsertAtIndex,
+ .AddCollection = (bool (*)(void *, PARCCollection *))NULL,
+ .AddCollectionAtIndex = (bool (*)(void *, int index, PARCCollection *))NULL,
+ .Clear = (void (*)(void *))NULL,
+ .Contains = (bool (*)(const void *, const PARCObject *))parcLinkedList_Contains,
+ .ContainsCollection = (bool (*)(const void *, const PARCCollection *))NULL,
+ .Copy = (void * (*)(const PARCList *))parcLinkedList_Copy,
+ .Destroy = (void (*)(void **))parcLinkedList_Release,
+ .Equals = (bool (*)(const void *, const void *))parcLinkedList_Equals,
+ .GetAtIndex = (PARCObject * (*)(const void *, size_t))parcLinkedList_GetAtIndex,
+ .HashCode = (PARCHashCode (*)(const void *))parcLinkedList_HashCode,
+ .IndexOf = (size_t (*)(const void *, const PARCObject *element))NULL,
+ .IsEmpty = (bool (*)(const void *))parcLinkedList_IsEmpty,
+ .LastIndexOf = (size_t (*)(void *, const PARCObject *element))NULL,
+ .Remove = (bool (*)(void *, const PARCObject *element))parcLinkedList_Remove,
+ .RemoveAtIndex = (PARCObject * (*)(PARCList *, size_t))parcLinkedList_RemoveAtIndex,
+ .RemoveCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .RetainCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .SetAtIndex = (PARCObject * (*)(void *, size_t index, PARCObject *))parcLinkedList_SetAtIndex,
+ .Size = (size_t (*)(const void *))parcLinkedList_Size,
+ .SubList = (PARCList * (*)(const void *, size_t, size_t))NULL,
+ .ToArray = (void** (*)(const void *))NULL,
+};
+
+typedef struct parc_linkedlist_node {
+ PARCObject *object;
+ struct parc_linkedlist_node *previous;
+ struct parc_linkedlist_node *next;
+} _PARCLinkedListNode;
+
+struct parc_linkedlist {
+ _PARCLinkedListNode *head;
+ _PARCLinkedListNode *tail;
+ size_t size;
+};
+
+static inline _PARCLinkedListNode *
+_parcLinkedListNode_getByIndex(const PARCLinkedList *list, size_t index)
+{
+ _PARCLinkedListNode *node = list->head;
+ while (index-- && node != NULL) {
+ node = node->next;
+ }
+ return node;
+}
+
+static inline _PARCLinkedListNode *
+_parcLinkedListNode_getByValue(const PARCLinkedList *list, const PARCObject *value)
+{
+ _PARCLinkedListNode *node = list->head;
+ while (node != NULL && parcObject_Equals(node->object, value) == false) {
+ node = node->next;
+ }
+ return node;
+}
+
+static bool
+_parcLinkedListNode_IsValid(const _PARCLinkedListNode *node)
+{
+ bool result = false;
+
+ if (node != NULL) {
+ if (node->object != NULL) {
+ if (parcObject_IsValid(node->object)) {
+ if (node->previous) {
+ if (node->previous->next == node) {
+ if (parcObject_IsValid(node->previous->object)) {
+ result = true;
+ }
+ }
+ } else {
+ result = true;
+ }
+ if (node->next != NULL) {
+ if (node->next->previous == node) {
+ if (parcObject_IsValid(node->next->object)) {
+ result = true;
+ }
+ }
+ } else {
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static inline _PARCLinkedListNode *
+_parcLinkedListNode_Create(const PARCObject *object, _PARCLinkedListNode *previous, _PARCLinkedListNode *next)
+{
+ _PARCLinkedListNode *result = parcMemory_Allocate(sizeof(_PARCLinkedListNode));
+ if (result != NULL) {
+ result->object = parcObject_Acquire(object);
+ result->next = next;
+ result->previous = previous;
+ }
+
+ return result;
+}
+
+static void
+_parcLinkedListIterator_IsValid(const _PARCLinkedListNode *node)
+{
+ if (node != NULL) {
+ assertTrue(_parcLinkedListNode_IsValid(node), "node is invalid");
+ }
+}
+
+static void
+_parcLinkedListNode_Destroy(PARCLinkedList *list __attribute__((unused)), _PARCLinkedListNode **nodePtr)
+{
+ _PARCLinkedListNode *node = *nodePtr;
+
+ parcObject_Release(&node->object);
+ parcMemory_Deallocate((void **) nodePtr);
+}
+
+static bool
+_parcLinkedList_Destructor(PARCLinkedList **listPtr)
+{
+ PARCLinkedList *list = *listPtr;
+
+ _PARCLinkedListNode *next = NULL;
+
+ for (_PARCLinkedListNode *node = list->head; node != NULL; node = next) {
+ next = node->next;
+ _parcLinkedListNode_Destroy(list, &node);
+ }
+ return true;
+}
+
+static _PARCLinkedListNode *
+_parcLinkedIterator_Init(PARCLinkedList *list __attribute__((unused)))
+{
+ return NULL;
+}
+
+static bool
+_parcLinkedListNode_Fini(PARCLinkedList *list __attribute__((unused)), const _PARCLinkedListNode *node __attribute__((unused)))
+{
+ return true;
+}
+
+static struct parc_linkedlist_node *
+_parcLinkedListNode_Next(PARCLinkedList *list __attribute__((unused)), const _PARCLinkedListNode *node)
+{
+ struct parc_linkedlist_node *result = NULL;
+
+ if (node == NULL) {
+ result = list->head;
+ } else {
+ assertTrue(_parcLinkedListNode_IsValid(node), "node is invalid");
+ trapOutOfBoundsIf(node->next == NULL, "No more elements.");
+ result = node->next;
+ }
+
+ assertTrue(_parcLinkedListNode_IsValid(result), "result is invalid");
+ parcObject_OptionalAssertValid(result->object);
+
+ return result;
+}
+
+static inline PARCObject *
+_parcLinkedListNode_Delete(PARCLinkedList *list, _PARCLinkedListNode *node)
+{
+ PARCObject *result = node->object;
+
+ list->size--;
+
+ if (node == list->head) {
+ list->head = node->next;
+ }
+ if (node == list->tail) {
+ list->tail = node->previous;
+ }
+ if (node->previous) {
+ node->previous->next = node->next;
+ }
+ if (node->next) {
+ node->next->previous = node->previous;
+ }
+
+ parcMemory_Deallocate((void **) &node);
+
+ return result;
+}
+
+static void
+_parcLinkedListNode_Remove(PARCLinkedList *list, _PARCLinkedListNode **nodePtr)
+{
+ parcLinkedList_OptionalAssertValid(list);
+
+ _PARCLinkedListNode *node = *nodePtr;
+
+ if (node != NULL) {
+ *nodePtr = node->previous;
+
+ PARCObject *object = _parcLinkedListNode_Delete(list, node);
+ parcObject_Release(&object);
+
+ parcLinkedList_OptionalAssertValid(list);
+ }
+}
+
+static bool
+_parcLinkedListNode_HasNext(PARCLinkedList *list, const _PARCLinkedListNode *node)
+{
+ bool result = false;
+
+ if (node == NULL) {
+ result = (list->head != NULL);
+ if (result) {
+ assertTrue(_parcLinkedListNode_IsValid(list->head), "node is invalid");
+ }
+ } else {
+ result = node->next != NULL;
+ if (result) {
+ assertTrue(_parcLinkedListNode_IsValid(node->next), "node is invalid");
+ }
+ }
+
+
+ return result;
+}
+
+static void *
+_parcLinkedListNode_Element(PARCLinkedList *list __attribute__((unused)), const _PARCLinkedListNode *node)
+{
+ return node->object;
+}
+
+parcObject_Override(PARCLinkedList, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcLinkedList_Destructor,
+ .copy = (PARCObjectCopy *) parcLinkedList_Copy,
+ .equals = (PARCObjectEquals *) parcLinkedList_Equals,
+ .hashCode = (PARCObjectHashCode *) parcLinkedList_HashCode,
+ .display = (PARCObjectDisplay *) parcLinkedList_Display);
+
+PARCIterator *
+parcLinkedList_CreateIterator(PARCLinkedList *list)
+{
+ PARCIterator *iterator = parcIterator_Create(list,
+ (void *(*)(PARCObject *))_parcLinkedIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcLinkedListNode_HasNext,
+ (void *(*)(PARCObject *, void *))_parcLinkedListNode_Next,
+ (void (*)(PARCObject *, void **))_parcLinkedListNode_Remove,
+ (void *(*)(PARCObject *, void *))_parcLinkedListNode_Element,
+ (void (*)(PARCObject *, void *))_parcLinkedListNode_Fini,
+ (void (*)(const void *))_parcLinkedListIterator_IsValid);
+
+ return iterator;
+}
+
+PARCLinkedList *
+parcLinkedList_Create(void)
+{
+ PARCLinkedList *result = parcObject_CreateInstance(PARCLinkedList);
+
+ if (result != NULL) {
+ result->head = NULL;
+ result->tail = NULL;
+ result->size = 0;
+ }
+ return result;
+}
+
+bool
+parcLinkedList_IsValid(const PARCLinkedList *list)
+{
+ bool result = false;
+
+ if (list != NULL) {
+ if (parcObject_IsValid(list)) {
+ if (list->size > 0) {
+ if (list->head != NULL) {
+ if (list->tail != NULL) {
+ result = true;
+ for (_PARCLinkedListNode *node = list->head; node != NULL; node = node->next) {
+ if (_parcLinkedListNode_IsValid(node) == false) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ if (list->head == NULL) {
+ if (list->tail == NULL) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void
+parcLinkedList_AssertValid(const PARCLinkedList *instance)
+{
+ assertTrue(parcLinkedList_IsValid(instance),
+ "PARCLinkedList is not valid.");
+}
+
+parcObject_ImplementAcquire(parcLinkedList, PARCLinkedList);
+
+parcObject_ImplementRelease(parcLinkedList, PARCLinkedList);
+
+PARCLinkedList *
+parcLinkedList_Copy(const PARCLinkedList *list)
+{
+ PARCLinkedList *result = parcLinkedList_Create();
+
+ struct parc_linkedlist_node *node = list->head;
+
+ while (node != NULL) {
+ parcLinkedList_Append(result, node->object);
+ node = node->next;
+ }
+
+ return result;
+}
+
+bool
+parcLinkedList_Contains(const PARCLinkedList *list, const PARCObject *element)
+{
+ bool result = false;
+
+ struct parc_linkedlist_node *node = list->head;
+
+ while (node != NULL) {
+ if (parcObject_Equals(node->object, element)) {
+ result = true;
+ break;
+ }
+ node = node->next;
+ }
+
+ return result;
+}
+
+PARCLinkedList *
+parcLinkedList_Append(PARCLinkedList *list, const PARCObject *element)
+{
+ _PARCLinkedListNode *node = _parcLinkedListNode_Create(element, list->tail, NULL);
+
+ if (list->tail == NULL) {
+ list->tail = node;
+ } else {
+ list->tail->next = node;
+ list->tail = node;
+ }
+
+ if (list->head == NULL) {
+ list->head = list->tail;
+ }
+
+ list->size++;
+
+ return list;
+}
+
+PARCLinkedList *
+parcLinkedList_AppendAll(PARCLinkedList *list, const PARCLinkedList *other)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator((PARCLinkedList *) other);
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *object = parcIterator_Next(iterator);
+ parcLinkedList_Append(list, object);
+ }
+ parcIterator_Release(&iterator);
+
+ return list;
+}
+
+PARCLinkedList *
+parcLinkedList_Prepend(PARCLinkedList *list, const PARCObject *element)
+{
+ _PARCLinkedListNode *node = _parcLinkedListNode_Create(element, NULL, list->head);
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->head->previous = node;
+ list->head = node;
+ }
+
+ if (list->tail == NULL) {
+ list->tail = list->head;
+ }
+ list->size++;
+
+ parcLinkedList_OptionalAssertValid(list);
+
+ return list;
+}
+
+PARCObject *
+parcLinkedList_RemoveFirst(PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->head != NULL) {
+ _PARCLinkedListNode *node = list->head;
+ result = _parcLinkedListNode_Delete(list, node);
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+
+ return result;
+}
+
+PARCObject *
+parcLinkedList_RemoveLast(PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->tail != NULL) {
+ _PARCLinkedListNode *node = list->tail;
+ result = _parcLinkedListNode_Delete(list, node);
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+ return result;
+}
+
+bool
+parcLinkedList_Remove(PARCLinkedList *list, const PARCObject *element)
+{
+ assertTrue(element != NULL, "Element must not be NULL");
+ bool result = false;
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByValue(list, element);
+ if (node != NULL) {
+ PARCObject *e = _parcLinkedListNode_Delete(list, node);
+ parcObject_Release(&e);
+ result = true;
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+
+ return result;
+}
+
+PARCObject *
+parcLinkedList_RemoveAtIndex(PARCLinkedList *list, size_t index)
+{
+ PARCObject *result = NULL;
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByIndex(list, index);
+ if (node != NULL) {
+ result = _parcLinkedListNode_Delete(list, node);
+ }
+
+ return result;
+}
+
+PARCObject *
+parcLinkedList_GetFirst(const PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->head != NULL) {
+ _PARCLinkedListNode *node = list->head;
+ result = node->object;
+ }
+ return result;
+}
+
+PARCObject *
+parcLinkedList_GetLast(const PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->tail != NULL) {
+ _PARCLinkedListNode *node = list->tail;
+ result = node->object;
+ }
+ return result;
+}
+
+PARCHashCode
+parcLinkedList_HashCode(const PARCLinkedList *list)
+{
+ PARCHashCode result = 0;
+
+ _PARCLinkedListNode *node = list->head;
+ if (node != NULL) {
+ while (node != NULL) {
+ result += parcObject_HashCode(node->object);
+ node = node->next;
+ }
+ }
+
+ return result;
+}
+
+size_t
+parcLinkedList_Size(const PARCLinkedList *list)
+{
+ return list->size;
+}
+
+bool
+parcLinkedList_IsEmpty(const PARCLinkedList *list)
+{
+ return (parcLinkedList_Size(list) == 0);
+}
+
+static void
+_parcLinkedList_InsertInitialNode(PARCLinkedList *list, const PARCObject *element)
+{
+ _PARCLinkedListNode *newNode = _parcLinkedListNode_Create(element, NULL, NULL);
+ list->head = newNode;
+ list->tail = newNode;
+}
+
+PARCLinkedList *
+parcLinkedList_InsertAtIndex(PARCLinkedList *list, size_t index, const PARCObject *element)
+{
+ if (index == 0) {
+ if (list->head == NULL) {
+ _parcLinkedList_InsertInitialNode(list, element);
+ } else {
+ _PARCLinkedListNode *newNode = _parcLinkedListNode_Create(element, NULL, list->head);
+
+ list->head->previous = newNode;
+ list->tail = list->head;
+ list->head = newNode;
+ }
+
+ list->size++;
+ } else if (index == list->size) {
+ _PARCLinkedListNode *node = list->tail;
+ node->next = _parcLinkedListNode_Create(element, node, NULL);
+ list->tail = node->next;
+ list->size++;
+ } else {
+ _PARCLinkedListNode *node = list->head;
+ while (index-- && node->next != NULL) {
+ node = node->next;
+ }
+ _PARCLinkedListNode *newNode = _parcLinkedListNode_Create(element, node->previous, node);
+
+ node->previous->next = newNode;
+ node->previous = newNode;
+ list->size++;
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+ return list;
+}
+
+PARCObject *
+parcLinkedList_SetAtIndex(PARCLinkedList *list, size_t index, PARCObject *element)
+{
+ PARCObject *result = NULL;
+
+ if (index > (parcLinkedList_Size(list) - 1)) {
+ trapOutOfBounds(index, "[0, %zd]", parcLinkedList_Size(list) - 1);
+ }
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByIndex(list, index);
+ if (node != NULL) {
+ result = node->object;
+ node->object = parcObject_Acquire(element);
+ }
+ return result;
+}
+
+PARCObject *
+parcLinkedList_GetAtIndex(const PARCLinkedList *list, size_t index)
+{
+ if (index > (parcLinkedList_Size(list) - 1)) {
+ trapOutOfBounds(index, "[0, %zd]", parcLinkedList_Size(list) - 1);
+ }
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByIndex(list, index);
+ return (node == NULL) ? NULL : node->object;
+}
+
+bool
+parcLinkedList_Equals(const PARCLinkedList *x, const PARCLinkedList *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->size == y->size) {
+ _PARCLinkedListNode *xNode = x->head;
+ _PARCLinkedListNode *yNode = y->head;
+
+ while (xNode != NULL) {
+ if (parcObject_Equals(xNode->object, yNode->object) == false) {
+ return false;
+ }
+ xNode = xNode->next;
+ yNode = yNode->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+parcLinkedList_Display(const PARCLinkedList *list, const int indentation)
+{
+ if (list == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCLinkedList@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCLinkedList@%p { .size=%016zp, .head=%016zp, .tail=%016zp",
+ (void *) list, list->size, list->head, list->tail);
+
+ _PARCLinkedListNode *node = list->head;
+
+ while (node != NULL) {
+ parcDisplayIndented_PrintLine(indentation + 1,
+ "%016zp { .previous=%016zp, %016zp, .next=%016zp }",
+ node, node->previous, node->object, node->next);
+ parcObject_Display(node->object, indentation + 2);
+ node = node->next;
+ }
+
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+ }
+}
+
+bool
+parcLinkedList_SetEquals(const PARCLinkedList *x, const PARCLinkedList *y)
+{
+ bool result = false;
+
+ if (x->size == y->size) {
+ for (size_t i = 0; i < x->size; i++) {
+ PARCObject *xObject = parcLinkedList_GetAtIndex(x, i);
+ for (size_t j = 0; j < x->size; j++) {
+ PARCObject *yObject = parcLinkedList_GetAtIndex(y, j);
+ if (parcObject_Equals(xObject, yObject) == false) {
+ break;
+ }
+ }
+ }
+ result = true;
+ }
+
+ return result;
+}
+
+PARCList *
+parcLinkedList_AsPARCList(PARCLinkedList *list)
+{
+ PARCList *result = parcList_Create(list, PARCLinkedListAsPARCList);
+ return result;
+}
+
+void
+parcLinkedList_ApplyImpl(PARCLinkedList *list, void (*function)(PARCObject *, const void *), const void *parameter)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator(list);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *object = parcIterator_Next(iterator);
+ function(object, parameter);
+ }
+
+ parcIterator_Release(&iterator);
+}
diff --git a/libparc/parc/algol/parc_LinkedList.h b/libparc/parc/algol/parc_LinkedList.h
new file mode 100644
index 00000000..7babff79
--- /dev/null
+++ b/libparc/parc/algol/parc_LinkedList.h
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_LinkedList.h
+ * @ingroup datastructures
+ * @brief PARC Double-ended Queue (Deque)
+ *
+ */
+#ifndef libparc_parc_LinkedList_h
+#define libparc_parc_LinkedList_h
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_linkedlist;
+/**
+ * A simple linked list.
+ *
+ * @see {@link parcLinkedList_Create}
+ */
+typedef struct parc_linkedlist PARCLinkedList;
+
+/**
+ * Create a `PARCLinkedList` instance with the default element equality and copy functions.
+ *
+ * The queue is created with no elements.
+ *
+ * The default element equals function is used by the `{@link parcLinkedList_Equals} function and
+ * simply compares the values using the `==` operator.
+ *
+ * @return non-NULL A pointer to a `PARCLinkedList` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCLinkedList *parcLinkedList_Create(void);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcLinkedList_OptionalAssertValid(_instance_)
+#else
+# define parcLinkedList_OptionalAssertValid(_instance_) parcLinkedList_AssertValid(_instance_)
+#endif
+void parcLinkedList_AssertValid(const PARCLinkedList *list);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the given PARCLinkedList.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] list A pointer to a valid `PARCLinkedList`.
+ *
+ * @see parcIterator_Release
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcLinkedList_CreateIterator(list);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcLinkedList_CreateIterator(PARCLinkedList *list);
+
+/**
+ * Acquire a new reference to an instance of `PARCLinkedList`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] list The instance of `PARCLinkedList` to which to refer.
+ *
+ * @return The same value as the input parameter @p deque
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Acquire(const PARCLinkedList *list);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] listPtr A pointer to a pointer to the instance of `PARCLinkedList` to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *buffer = parcLinkedList_Create(10);
+ *
+ * parcLinkedList_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcLinkedList_Release(PARCLinkedList **listPtr);
+
+/**
+ * Copy a a `PARCLinkedList` to another.
+ *
+ * @param [in] list A pointer to an instance of `PARCLinkedList`
+ *
+ * @return A pointer to a copy of the original instance of `PARCLinkedList`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Copy(const PARCLinkedList *list);
+
+/**
+ * Determine if an instance of `PARCLinkedList` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] list A pointer to a `PARCLinkedList` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *instance = parcLinkedList_Create();
+ *
+ * if (parcLinkedList_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcLinkedList_IsValid(const PARCLinkedList *list);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of the `HashCode` function is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information in the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the `Equals` function,
+ * then calling the `HashCode` function on each of the two instances must produce the same result.
+ *
+ * It is not required that if two instances are unequal according to the `Equals` function,
+ * then calling the `HashCode` function
+ * on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to the `PARCLinkedList` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *buffer = parcLinkedList_Allocate(10);
+ * PARCHashCode hash = parcLinkedList_HashCode(buffer);
+ * parcLinkedList_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCHashCode parcLinkedList_HashCode(const PARCLinkedList *instance);
+
+/**
+ * Returns true if the given `PARCLinkedList` contains the specified `PARCObject`.
+ *
+ * The semantics are such that the function returns `true` if and only if the `PARCLinkedList`
+ * list contains at least one `PARCObject` _o_ such that PARCObject_Equals(_o_, object) is true.
+ *
+ * @param [in] list A pointer to a valid `PARCLinkedList` instance.
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The given `PARCLinkedList` contains the specified `PARCObject`.
+ * @return false The given `PARCLinkedList` does not contain the specified `PARCObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcLinkedList_Contains(const PARCLinkedList *list, const PARCObject *object);
+
+/**
+ * Append an element to the tail end of the specified `PARCLinkedList`
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` to which the element will be appended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCLinkedList`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCLinkedList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Append(PARCLinkedList *list, const PARCObject *element);
+
+/**
+ * Append each element from the PARCLinkedList @p other to @p list.
+ *
+ * @param [in] list A pointer to a valid PARCLinkedList instance that will be receive each element from @p other.
+ * @param [in] other A pointer to a valid PARCLinkedList instance containing the elements to append to @p list.
+ *
+ * @return The value of @p list.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_AppendAll(PARCLinkedList *list, const PARCLinkedList *other);
+
+/**
+ * Prepend an element to the head end of the specified `PARCLinkedList`
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` to which the element will be prepended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCLinkedList`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCLinkedList`
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Prepend(PARCLinkedList *list, const PARCObject *element);
+
+/**
+ * Return the first element of the specified `PARCLinkedList` and remove it from the list.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the first element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_RemoveFirst(PARCLinkedList *list);
+
+/**
+ * Remove the last element in the queue and return it.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the last element will be removed and returned.
+ *
+ * @return non-NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_RemoveLast(PARCLinkedList *list);
+
+/**
+ * Remove the first occurrence of the given element from the specified 'PARCLinkedList'.
+ * The element's reference count is decremented.
+ *
+ * @param [in] element the element to remove
+ * @return true if the element was found in the list and successfully removed
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *list = parcLinkedList_Create();
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapCString("1");
+ * parcLinkedList_Append(list, buffer);
+ * parcBuffer_Release(&buffer);
+ * // ...
+ * PARCBuffer *actual = parcLinkedList_Remove(list, buffer);
+ * parcBuffer_Release(&actual);
+ *
+ * // ...
+ *
+ * parcLinkedList_Release(&list);
+ * }
+ * @endcode
+ */
+bool parcLinkedList_Remove(PARCLinkedList *list, const PARCObject *element);
+
+/**
+ * Removes the element at the specified position in this list.
+ *
+ * Shifts all subsequent elements to the left (subtracts one from their indices).
+ * Return the element that was removed from the list without modifying the reference count.
+ * The caller must eventually release the returned value.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the element will be removed.
+ * @param [in] index The index (origin 0) of the element to remove.
+ *
+ * @return The element that was removed from the list.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *list = parcLinkedList_Create();
+ * // add elements to the list.
+ *
+ * parcLinkedList_RemoveAtIndex(list, 2); // remove the 3rd element in the list.
+ *
+ * // ...
+ *
+ * parcLinkedList_Release(&list);
+ * }
+ * @endcode
+ */
+PARCObject *parcLinkedList_RemoveAtIndex(PARCLinkedList *list, size_t index);
+
+/**
+ * Return the first element of the specified `PARCLinkedList` but do NOT remove it from the queue
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the first element will be returned
+ *
+ * @return non NULL A pointer to the first element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_GetFirst(const PARCLinkedList *list);
+
+/**
+ * Return the last element of the specified `PARCLinkedList` but do NOT remove it from the queue
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the last element will be returned
+ *
+ * @return non NULL A pointer to the last element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_GetLast(const PARCLinkedList *list);
+
+/**
+ * Return the size of the specified queue
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList`
+ *
+ * @return `size_t` The size of the queue
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+size_t parcLinkedList_Size(const PARCLinkedList *list);
+
+/**
+ * Return True if the `PARCLinkedList` is empty or False if not.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList`
+ *
+ * @return bool True if the `PARCLinkedList` is empty or False if not.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+bool parcLinkedList_IsEmpty(const PARCLinkedList *list);
+
+/**
+ * Get a pointer to the specified element.
+ *
+ * @param [in] list A pointer to a `PARCLinkedList` instance.
+ * @param [in] index The index of the element to be retrieved.
+ *
+ * @throws `trapOutOfBounds`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcLinkedList_GetAtIndex(const PARCLinkedList *list, size_t index);
+
+/**
+ * Replace the element at the specified position in this list with the given element.
+ *
+ * @param [in] list A pointer to a `PARCLinkedList` instance.
+ * @param [in] index The index of the element to be replaced.
+ * @param [in] element A pointer to a valid PARCObject instance that will replace the current element at @p index.
+ *
+ * @throws `trapOutOfBounds`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcLinkedList_SetAtIndex(PARCLinkedList *list, size_t index, PARCObject *element);
+
+/**
+ * Determine if two `PARCLinkedList` instances are equal.
+ *
+ * This function implements the following equivalence relations on non-null `PARCLinkedList` instances:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcLinkedList_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcLinkedList_Equals(x, y)` must return true if and only if
+ * `parcLinkedList_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcLinkedList_Equals(x, y)` returns true and
+ * `parcLinkedList_Equals(y, z)` returns true,
+ * then `parcLinkedList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcLinkedList_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcLinkedList_Equals(x, NULL)` must return false.
+ *
+ * Two `PARCLinkedList` instances with different element equality functions are always unequal.
+ *
+ * @param [in] x A pointer to a `PARCLinkedList` instance.
+ * @param [in] y A pointer to a `PARCLinkedList` instance.
+ *
+ * @return true `PARCLinkedList` x and y are equal.
+ * @return false `PARCLinkedList` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcLinkedList_Equals(const PARCLinkedList *x, const PARCLinkedList *y);
+
+/**
+ * Print a human readable representation of the given `PARCLinkedList`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] list A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *instance = parcLinkedList_Create();
+ *
+ * parcLinkedList_Display(instance, 0);
+ *
+ * parcLinkedList_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcLinkedList_Display(const PARCLinkedList *list, int indentation);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcLinkedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCLinkedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcLinkedList_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcLinkedList, PARCLinkedList);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcLinkedList_Wait`, `parcLinkedList_WaitFor`, `parcLinkedList_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcLinkedList_Lock(object)) {
+ * parcLinkedList_NotifyAll(object);
+ * parcLinkedList_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcLinkedList, PARCLinkedList);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcLinkedList_Notify() function on the same object.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcLinkedList_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcLinkedList, PARCLinkedList);
+
+parcObject_ImplementWaitFor(parcLinkedList, PARCLinkedList);
+
+parcObject_ImplementWaitUntil(parcLinkedList, PARCLinkedList);
+
+/**
+ * Obtain the lock on the given `PARCLinkedList` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCLinkedList` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcLinkedList_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcLinkedList, PARCLinkedList);
+
+/**
+ * Try to obtain the advisory lock on the given PARCLinkedList instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCLinkedList instance.
+ *
+ * @return true The PARCLinkedList is locked.
+ * @return false The PARCLinkedList is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcLinkedList_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcLinkedList, PARCLinkedList);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCLinkedList` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * @return true The `PARCLinkedList` was locked and now is unlocked.
+ * @return false The `PARCLinkedList` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcLinkedList_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcLinkedList, PARCLinkedList);
+
+/**
+ * Determine if the advisory lock on the given `PARCLinkedList` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * @return true The `PARCLinkedList` is locked.
+ * @return false The `PARCLinkedList` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcLinkedList_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcLinkedList, PARCLinkedList);
+
+/**
+ * Determine if two `PARCLinkedList` instances are equivalent sets.
+ *
+ * The lists are examined without regard to order.
+ * If both lists, x and y are of equal length, and all of the elements in list `x` are present in list `y`, this function returns true.
+ *
+ * @param [in] x A pointer to a valid `PARCLinkedList` instance.
+ * @param [in] y A pointer to a valid `PARCLinkedList` instance.
+ * @return true The instances are equivalent.
+ * @return false The instances are equivalent.
+ *
+ */
+bool parcLinkedList_SetEquals(const PARCLinkedList *x, const PARCLinkedList *y);
+
+/**
+ * Insert the given element into the list such that it is the index'th element in the list.
+ */
+PARCLinkedList *parcLinkedList_InsertAtIndex(PARCLinkedList *list, size_t index, const PARCObject *element);
+
+/**
+ * Apply a function to every element in the given PARCLinkedList.
+ *
+ * The function is applied in order, any return value is ignored.
+ *
+ * @param [in] list A pointer to a valid PARCLinkedList instance.
+ * @param [in] function A pointer to a function that will be called with each element of the list.
+ * @param [in] parameter A pointer to arbitrary data that will supplied as an additional parameter to @p function
+ *
+ */
+#define parcLinkedList_Apply(_list_, _function_, _parameter_) \
+ parcLinkedList_ApplyImpl(_list_, (void (*))_function_, (const void *) _parameter_)
+void parcLinkedList_ApplyImpl(PARCLinkedList *list, void (*function)(PARCObject *, const void *), const void *parameter);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCList *parcLinkedList_AsPARCList(PARCLinkedList *list);
+#endif // libparc_parc_Deque_h
diff --git a/libparc/parc/algol/parc_List.c b/libparc/parc/algol/parc_List.c
new file mode 100644
index 00000000..0e62cda6
--- /dev/null
+++ b/libparc/parc/algol/parc_List.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_list {
+ void *instance;
+ const PARCListInterface *interface;
+};
+
+static void
+_destroy(PARCList **listPtr)
+{
+ PARCList *list = *listPtr;
+
+ (list->interface->Destroy)(&list->instance);
+}
+
+parcObject_ExtendPARCObject(PARCList, _destroy, parcList_Copy, NULL, parcList_Equals, NULL, parcList_HashCode, NULL);
+
+PARCList *
+parcList(void *instance, PARCListInterface *interface)
+{
+ PARCList *result = parcObject_CreateInstance(PARCList);
+ if (result != NULL) {
+ result->instance = instance;
+ result->interface = interface;
+ }
+
+ return result;
+}
+
+PARCList *
+parcList_Create(PARCObject *instance, PARCListInterface *interface)
+{
+ PARCList *result = parcObject_CreateInstance(PARCList);
+ if (result != NULL) {
+ result->instance = parcObject_Acquire(instance);
+ result->interface = interface;
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcList, PARCList);
+
+parcObject_ImplementRelease(parcList, PARCList);
+
+PARCList *
+parcList_Copy(const PARCList *list)
+{
+ PARCList *result = parcObject_CreateInstance(PARCList);
+ if (result != NULL) {
+ result->instance = (list->interface->Copy)(list->instance);
+ result->interface = list->interface;
+ }
+
+ return result;
+}
+
+bool
+parcList_IsEmpty(const PARCList *list)
+{
+ bool result = false;
+ if (list->interface->IsEmpty) {
+ result = (list->interface->IsEmpty)(list->instance);
+ } else {
+ result = (parcList_Size(list) == 0);
+ }
+ return result;
+}
+
+bool
+parcList_Add(PARCList *list, void *element)
+{
+ return (list->interface->Add)(list->instance, element);
+}
+
+bool
+parcList_AddAll(PARCList *list, size_t argc, void *argv[argc])
+{
+ for (int i = 0; i < argc; i++) {
+ (list->interface->Add)(list->instance, argv[i]);
+ }
+ return true;
+}
+
+void
+parcList_AddAtIndex(PARCList *list, int index, void *element)
+{
+ (list->interface->AddAtIndex)(list->instance, index, element);
+}
+
+bool
+parcList_AddCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->AddCollection)(list->instance, collection);
+}
+
+bool
+parcList_AddCollectionAtIndex(PARCList *list, int index, PARCCollection *collection)
+{
+ return (list->interface->AddCollectionAtIndex)(list->instance, index, collection);
+}
+
+void
+parcList_Clear(PARCList *list)
+{
+ if (!list->interface->Clear) {
+ for (size_t i = 0; i < parcList_Size(list); i++) {
+ parcList_RemoveAtIndex(list, i);
+ }
+ } else {
+ (list->interface->Clear)(list->instance);
+ }
+}
+
+bool
+parcList_Contains(const PARCList *list, void *element)
+{
+ return (list->interface->Contains)(list->instance, element);
+}
+
+bool
+parcList_ContainsCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->ContainsCollection)(list->instance, collection);
+}
+
+bool
+parcList_Equals(const PARCList *x, const PARCList *y)
+{
+ return (x->interface->Equals)(x->instance, y->instance);
+}
+
+void *
+parcList_GetAtIndex(const PARCList *list, size_t index)
+{
+ return (list->interface->GetAtIndex)(list->instance, index);
+}
+
+int
+parcList_HashCode(const PARCList *list)
+{
+ return (list->interface->HashCode)(list->instance);
+}
+
+ssize_t
+parcList_IndexOf(const PARCList *list, PARCObject *element)
+{
+ ssize_t result = -1;
+
+ if (list->interface->IndexOf) {
+ result = (list->interface->IndexOf)(list->instance, element);
+ } else {
+ for (ssize_t i = 0; i < parcList_Size(list); i++) {
+ PARCObject *e = parcList_GetAtIndex(list, i);
+ if (parcObject_Equals(e, element)) {
+ result = i;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+ssize_t
+parcList_LastIndexOf(const PARCList *list, PARCObject *element)
+{
+ ssize_t result = -1;
+
+ if (list->interface->LastIndexOf) {
+ result = (list->interface->LastIndexOf)(list->instance, element);
+ } else {
+ for (ssize_t i = parcList_Size(list) - 1; i >= 0; i--) {
+ PARCObject *e = parcList_GetAtIndex(list, i);
+ if (parcObject_Equals(e, element)) {
+ result = i;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCObject *
+parcList_RemoveAtIndex(PARCList *list, size_t index)
+{
+ if (list->interface->RemoveAtIndex) {
+ return (list->interface->RemoveAtIndex)(list->instance, index);
+ } else {
+ return NULL;
+ }
+}
+
+bool
+parcList_Remove(PARCList *list, PARCObject *element)
+{
+ bool result = false;
+
+ if (list->interface->Remove != NULL) {
+ result = (list->interface->Remove)(list->instance, element);
+ } else {
+ for (size_t i = 0; i < parcList_Size(list); i++) {
+ void *e = parcList_GetAtIndex(list, i);
+ if (parcObject_Equals(e, element)) {
+ parcList_RemoveAtIndex(list, i);
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcList_RemoveCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->RemoveCollection)(list->instance, collection);
+}
+
+bool
+parcList_RetainCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->RetainCollection)(list->instance, collection);
+}
+
+PARCObject *
+parcList_SetAtIndex(PARCList *list, size_t index, void *element)
+{
+ return (list->interface->SetAtIndex)(list->instance, index, element);
+}
+
+size_t
+parcList_Size(const PARCList *list)
+{
+ return (list->interface->Size)(list->instance);
+}
+
+PARCList *
+parcList_SubList(PARCList *list, size_t fromIndex, size_t toIndex)
+{
+ return (list->interface->SubList)(list->instance, fromIndex, toIndex);
+}
+
+void**
+parcList_ToArray(PARCList *list)
+{
+ return (list->interface->ToArray)(list->instance);
+}
diff --git a/libparc/parc/algol/parc_List.h b/libparc/parc/algol/parc_List.h
new file mode 100644
index 00000000..6c17453c
--- /dev/null
+++ b/libparc/parc/algol/parc_List.h
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @file parc_List.h
+ * @ingroup datastructures
+ * @brief PARC (Generic) List
+ *
+ * An ordered collection (also known as a sequence).
+ * The user of this interface has precise control over where in the list each element is inserted.
+ * The user can access elements by their integer index (position in the list), and search for elements in the list.
+ * Unlike sets, lists typically allow duplicate elements.
+ * More formally, lists typically allow pairs of elements e1 and e2 such that e1.equals(e2), and they typically allow
+ * multiple null elements if they allow null elements at all.
+ * It is not inconceivable that someone might wish to implement a list that prohibits duplicates,
+ * by throwing runtime exceptions when the user attempts to insert them, but we expect this usage to be rare.
+ *
+ */
+#ifndef libparc_parc_List_h
+#define libparc_parc_List_h
+
+#include <stdbool.h>
+
+struct parc_list;
+/**
+ * @typedef PARCList
+ * @brief An ordered collection (also known as a sequence).
+ */
+typedef struct parc_list PARCList;
+
+#include <parc/algol/parc_HashCode.h>
+
+#include <parc/algol/parc_Collection.h>
+#include <parc/algol/parc_Object.h>
+
+/**
+ * @typedef PARCListInterface
+ * @brief The interface of a `PARCList` including functions such as copy, destroy, add, etc.
+ */
+typedef struct parc_list_interface {
+ /**
+ * Copy an instance of `PARCList`
+ *
+ * @param [in] original An instance of `PARCList` to copy
+ *
+ * @return A pointer to the new list.
+ */
+ void *(*Copy)(const PARCList * original);
+
+ /**
+ * Destroy the List
+ *
+ * @param [in,out] instancePtr
+ * @return a pointer to the destroyed List.
+ */
+ void (*Destroy)(void **instancePtr);
+
+ /**
+ * Tests if this list is empty.
+ *
+ * @param [in] instance
+ * @return true if the list is empty
+ */
+ bool (*IsEmpty)(const void *instance);
+
+ /**
+ * Appends the specified element to the end of this list (optional operation).
+ *
+ * @param [in,out] The instance of `PARCList` to append the element to
+ * @param [in] element The pointer to the element to be added to the `PARCList`
+ * @return true if the element was added successfully.
+ */
+ bool (*Add)(void *instance, PARCObject *element);
+
+ /**
+ * Inserts the specified element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] instance The instance of `PARCList` to modify
+ * @param [in] index The index in `PARCList` at which to insert the @p element
+ * @param [in] element The element to insert in `PARCList` at @p index.
+ */
+ void (*AddAtIndex)(void *instance, int index, PARCObject *element);
+
+ /**
+ * Append elements of @p collection to @p instance
+ *
+ * Appends all of the elements in the specified collection to the end of this list,
+ * in the order that they are returned by the specified collection's iterator (optional operation).
+ *
+ * @param [in,out] instance The `PARCList` to be modified
+ * @param [in] collection The collection to be added
+ * @return true if add is successful.
+ */
+ bool (*AddCollection)(void *instance, PARCCollection *collection);
+
+ /**
+ * Inserts all of the elements in the specified collection into this list at the specified position (optional operation)
+ *
+ * @param [in,out] instance The `PARCList` to be modified
+ * @param [in] index The position at which to insert the @p collection
+ * @param [in] collection The collection to be added
+ * @return true if add is successful.
+ * @endcode
+ */
+ bool (*AddCollectionAtIndex)(void *instance, int index, PARCCollection *collection);
+
+ /**
+ * Removes all of the elements from this list (optional operation).
+ *
+ * @param [in,out] instance The instance of `PARCList` to empty.
+ */
+ void (*Clear)(void *instance);
+
+ /**
+ * Returns true if this list contains the specified element.
+ *
+ * @param [in] instance The instance of `PARCList` to inspect
+ * @param [in] element The element to search for in @p instance
+ * @return true if the @p element is found in @p instance.
+ */
+ bool (*Contains)(const void *instance, const PARCObject *element);
+
+ /**
+ * Returns true if this list contains all of the elements of the specified collection.
+ *
+ * @param [in] instance The instance of `PARCList` to inspect
+ * @param [in] collection The instance of {@link PARCCollection} whose elements are sought in @p instance
+ * @return true if all of the elements in @p collection is found in @p instance
+ */
+ bool (*ContainsCollection)(const void *instance, const PARCCollection *collection);
+
+ /**
+ * Compares the specified object with this list for equality.
+ *
+ * @param [in] xInstance The first `PARCList` instance to compare
+ * @param [in] yInstance The second `PARCList` instance to compare
+ * @return true if the two instances are equal
+ */
+ bool (*Equals)(const void *xInstance, const void *yInstance);
+
+ /**
+ * Returns the element at the specified position in this list.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @param index The index of the element to be returned
+ * @return A pointer to the element at @p index
+ */
+ PARCObject *(*GetAtIndex)(const void *instance, size_t index);
+
+ /**
+ * Returns the hash code value for this list.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @return int The hash code value
+ */
+ PARCHashCode (*HashCode)(const void *instance);
+
+ /**
+ * Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @param [in] element A pointer to the element to locate in @p instance
+ * @return size_t the index of the first located @p element or -1 if not found
+ */
+ size_t (*IndexOf)(const void *instance, const PARCObject *element);
+
+ /**
+ * Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @param [in] element A pointer to the element to locate in @p instance
+ * @return size_t the index of the last located @p element or -1 if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ size_t (*LastIndexOf)(void *instance, const PARCObject *element);
+
+ /**
+ * Removes the element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param [in] index The index of the element to remove
+ * @return A pointer to the removed element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ PARCObject *(*RemoveAtIndex)(PARCList * list, size_t index);
+
+ /**
+ * Removes the first occurrence of the specified element from this list, if it is present (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param element The element to find and remove
+ * @return true if element found and removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*Remove)(void *instance, const PARCObject *element);
+
+ /**
+ * Removes from this list all of its elements that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param collection The instance of {@link PARCCollection} whose elements should be found in the @p instance and removed.
+ * @return true if the elements are found and removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*RemoveCollection)(void *instance, const PARCCollection *collection);
+
+ /**
+ * Retains only the elements in this list that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param collection The instance of {@link PARCCollection} whose elements should be retained in
+ * the @p instance while all other elements are removed.
+ * @return true if the operation is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*RetainCollection)(void *instance, const PARCCollection *collection);
+
+ /**
+ * Replaces the element at the specified position in this list with the specified element (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param index The position in @p instance to replace with @p element
+ * @param element The element to put into @p instance at @p index, replacing the current value.
+ * @return
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void *(*SetAtIndex)(void *instance, size_t index, PARCObject * element);
+
+ /**
+ * Returns the number of elements in this list.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList` to inspect
+ * @return size_t Number of elements in the list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ size_t (*Size)(const void *instance);
+
+ /**
+ * Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList` to inspect
+ * @param [in] fromIndex The starting index into the list
+ * @param [in] toIndex The end index into the list
+ * @return A pointer to the sub list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ PARCList *(*SubList)(const void *instance, size_t fromIndex, size_t toIndex);
+
+ /**
+ * Returns an array containing all of the elements in this list in proper sequence (from first to last element).
+ *
+ * @param [in] instance A pointer to the instance of `PARCList` to inspect
+ * @return A pointer to a pointer to the array containing the elements of the list in proper sequence.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void** (*ToArray)(const void *instance);
+} PARCListInterface;
+
+/**
+ * Increase the number of references to a `PARCList`.
+ *
+ * Note that new `PARCList` is not created,
+ * only that the given `PARCList` reference count is incremented.
+ * Discard the reference by invoking `parcList_Release`.
+ *
+ * @param list A pointer to the original `PARCList`.
+ * @return The value of the input parameter @p list.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+ *
+ * PARCList *list2 = parcList_Acquire(list);
+ *
+ * parcList_Release(&list);
+ * parcList_Release(&list2);
+ * }
+ * @endcode
+ *
+ * @see parcList_Release
+ */
+PARCList *parcList_Acquire(const PARCList *list);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] listPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+ *
+ * parcList_Release(&list);
+ * }
+ * @endcode
+ */
+void parcList_Release(PARCList **listPtr);
+
+/**
+ * Create an independent copy the given `PARCList`
+ *
+ * A new list is created as a complete copy of the original.
+ *
+ * @param [in] list A valid pointer to a `PARCList` instance (cannot be NULL)
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCList` instance.
+ *
+ * @throws trapIllegalValue if @p instance is NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+ *
+ * PARCList *copy = parcList_Copy(list);
+ *
+ * parcList_Release(&copy);
+ * parcList_Release(&list);
+ * }
+ * @endcode
+ *
+ */
+PARCList *parcList_Copy(const PARCList *list);
+
+/**
+ * Tests if this list is empty.
+ *
+ * Return true if the list is empty, false otherwise
+ *
+ * @param list A pointer to the instance of `PARCList` to test
+ * @return True if the list is empty, else False
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_IsEmpty(const PARCList *list);
+
+/**
+ * Appends the specified element to the end of this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the instance of `PARCList` to modify
+ * @param [in] element The element to add to the end of the `PARCList`
+ * @return True if the add is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_Add(PARCList *list, void *element);
+
+/**
+ * Add all of the pointers in the given array of pointers to the `PARCList`.
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] argc The number of values in @p argv.
+ * @param [in] argv An array void * values.
+ *
+ * @return True if the add is successful
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+ *
+ * int elements[] = { 1, 2, 3 };
+ *
+ * parcList_AddAll(array, 3, elements);
+ * size_t actual = parcList_Length(array);
+ *
+ * assertTrue(3 == actual, "Expected=%d, actual=%d", 3, actual);
+ *
+ * parcListRelease(&array);
+ * }
+ * @endcode
+ */
+bool parcList_AddAll(PARCList *list, size_t argc, void **argv);
+
+/**
+ * Inserts the specified element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified
+ * @param [in] index The specified position in the list
+ * @param [in] element The element to be added to the specified position.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcList_AddAtIndex(PARCList *list, int index, void *element);
+
+/**
+ * Appends all of the elements in the specified collection to the end of this list,
+ * in the order that they are returned by the specified collection's iterator (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified
+ * @param [in] collection A pointer to an istance of {@link PARCCollection} to be added to the list
+ * @return True if add is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_AddCollection(PARCList *list, PARCCollection *collection);
+
+/**
+ * Inserts all of the elements in the specified collection into this list at the specified position (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified
+ * @param [in] index The position at which to insert the collection
+ * @param [in] collection A pointer to an istance of {@link PARCCollection} to be inserted into the list
+ * @return True if insertion is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_AddCollectionAtIndex(PARCList *list, int index, PARCCollection *collection);
+
+/**
+ * Removes all of the elements from this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be cleared
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcList_Clear(PARCList *list);
+
+/**
+ * Returns true if this list contains the specified element.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be checked
+ * @param [in] element The element to be added to the specified position.
+ * @return True if the element is contained in the list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_Contains(const PARCList *list, void *element);
+
+/**
+ * Returns true if this list contains all of the elements of the specified collection.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be checked
+ * @param [in] collection A pointer to the instance of {@link PARCCollection} to be checked.
+ * @return True if all of the elements in the collection are found in the list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_ContainsCollection(PARCList *list, PARCCollection *collection);
+
+
+/**
+ * Determine if two `PARCList` instances are equal.
+ *
+ * Two `PARCList` instances are equal if, and only if,
+ * the size of the lists are equal and each element in the list is equal and
+ * in the same order.
+ *
+ * The following equivalence relations on non-null `PARCList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcList_Equals(x, y)` must return true if and only if
+ * `parcList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcList_Equals(x, y)` returns true and
+ * `parcList_Equals(y, z)` returns true,
+ * then `parcList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCList` instance.
+ * @param [in] y A pointer to a `PARCList` instance.
+ * @return true if the two `PARCList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *a = parcList_Create();
+ * PARCList *b = parcList_Create();
+ *
+ * if (parcList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcList_Equals(const PARCList *x, const PARCList *y);
+
+/**
+ * Returns the element at the specified position in this list.
+ * If the index is out of bounds, it will trap with an out-of-bounds.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be checked
+ * @param [in] index The index of the element to be returned
+ * @return A pointer to the element.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcList_GetAtIndex(const PARCList *list, size_t index);
+
+/**
+ * Returns the hash code value for this list.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be hashed
+ * @return The hash code value
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcList_HashCode(const PARCList *list);
+
+/**
+ * Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be hashed.
+ * @param [in] element A pointer to an element to check for list inclusion.
+ * @return The index of the first occurance of @p element, or -1 if it is not present
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t parcList_IndexOf(const PARCList *list, PARCObject *element);
+
+/**
+ * Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be hashed.
+ * @param [in] element A pointer to an element to check for list inclusion.
+ * @return The index of the last occurance of @p element, or -1 if it is not present
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t parcList_LastIndexOf(const PARCList *list, PARCObject *element);
+
+/**
+ * Removes the element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] index The index of the element to be removed
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcList_RemoveAtIndex(PARCList *list, size_t index);
+
+/**
+ * Removes the first occurrence of the specified element from this list, if it is present (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] element A pointer to the element to be removed from the `PARCList`
+ * @return true The element was found and removed, false if it was not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_Remove(PARCList *list, PARCObject *element);
+
+/**
+ * Removes from this list all of its elements that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] collection A pointer to the instance of {@link PARCCollection} to be removed from the `PARCList`
+ * @return true The collection was found and removed, false if it was not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_RemoveCollection(PARCList *list, PARCCollection *collection);
+
+/**
+ * Retains only the elements in this list that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] collection A pointer to the instance of {@link PARCCollection} to be found and retained in the `PARCList`
+ * @return true if the function was successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_RetainCollection(PARCList *list, PARCCollection *collection);
+
+/**
+ * Replaces the element at the specified position in this list with the specified element (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] index The position at which the element should be replaced with @p element
+ * @param [in] element A pointer to the element to be inserted at the specified position
+ * @return A pointer to the element previously at that position.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcList_SetAtIndex(PARCList *list, size_t index, PARCObject *element);
+
+/**
+ * Returns the number of elements in this list.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be measured.
+ * @return The size of the @p list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcList_Size(const PARCList *list);
+
+/**
+ * Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be measured.
+ * @param [in] fromIndex The position to start the view (inclusive)
+ * @param [in] toIndex The position to end the view (exclusive)
+ * @return a pointer to an instance of `PARCList` containing the subList requested
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCList *parcList_SubList(PARCList *list, size_t fromIndex, size_t toIndex);
+
+/**
+ * Returns an array containing all of the elements in this list in proper sequence (from first to last element).
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be sorted.
+ * @return A pointer to a pointer to an Array containing the sorted elements
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void**parcList_ToArray(PARCList *list);
+
+/**
+ * Create an instance of `PARCList` that uses the @p interface to provide functions and the @p instance to provide
+ * initial elements of the list.
+ * @param [in] instance An initial set of elements for the new instance of `PARCList`
+ * @param [in] interface A pointer to an instance of {@link PARCListInterface} containing a set of list functions
+ * @return A pointer to a new instance of `PARCList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCList *parcList(void *instance, PARCListInterface *interface);
+
+/**
+ * Create an instance of `PARCList` that uses the @p interface to provide functions and the @p instance to provide
+ * initial elements of the list.
+ * @param [in] instance An initial set of elements for the new instance of `PARCList`
+ * @param [in] interface A pointer to an instance of {@link PARCListInterface} containing a set of list functions
+ * @return A pointer to a new instance of `PARCList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCList *parcList_Create(void *instance, PARCListInterface *interface);
+
+#endif // libparc_parc_List_h
diff --git a/libparc/parc/algol/parc_Map.c b/libparc/parc/algol/parc_Map.c
new file mode 100755
index 00000000..e5371c99
--- /dev/null
+++ b/libparc/parc/algol/parc_Map.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Map.h>
diff --git a/libparc/parc/algol/parc_Map.h b/libparc/parc/algol/parc_Map.h
new file mode 100755
index 00000000..c63b23c5
--- /dev/null
+++ b/libparc/parc/algol/parc_Map.h
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Map.h
+ * @ingroup datastructures
+ * @brief An object that maps keys to values.
+ *
+ * A map cannot contain duplicate keys; each key can map to at most one value.
+ *
+ */
+#ifndef libparc_parc_Map_h
+#define libparc_parc_Map_h
+#include <stdbool.h>
+
+struct parc_map;
+typedef struct parc_map PARCMap;
+
+typedef struct parc_map_interface {
+ /**
+ * Removes all of the mappings from this map.
+ *
+ * The map will be empty after this call returns.
+ *
+ * @param [in,out] map The instance of `PARCMap` to be cleared of mappings
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ void (*parcMap_Clear)(PARCMap *map);
+
+ /**
+ * Returns true if this map contains a mapping for the specified key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] key A pointer to the key to check for in @p map
+ *
+ * @return True if the map cnatins a mapping for the specified key
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ bool (*parcMap_ContainsKey)(PARCMap *map, void *key);
+
+ /**
+ * Returns true if this map maps one or more keys to the specified value.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] value A pointer to the value to check for in @p map
+ *
+ * @return True if the map contains one or more keys that map to @p value.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ bool (*parcMap_ContainsValue)(PARCMap *map, void *value);
+
+ /**
+ * Compares the specified object with this map for equality.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] other A pointer to the other instance of `PARCMap` to compare
+ * @return True is the two maps are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ bool (*parcMap_Equals)(PARCMap *map, void *other);
+
+ /**
+ * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] key A pointer to the key to check for in @p map
+ *
+ * @return NULL If the @p key is not present in @p map
+ * @return NOT NULL The value to which the @p key is mapped.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ void *(*parcMap_Get)(PARCMap * map, void *key);
+
+ /**
+ * Returns the hash code value for this map.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to hash
+ *
+ * @return The hash of the instance of `PARCMap`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ int (*parcMap_HashCode)(PARCMap *map);
+
+ /**
+ * Returns true if this map contains no key-value mappings.
+ *
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ *
+ * @return True if the map contains no mappings.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ bool (*parcMap_IsEmpty)(PARCMap *map);
+
+ /**
+ * Associates the specified value with the specified key in this map (optional operation).
+ *
+ * @param [in,out] map A pointer to the instance of `PARCMap` in which to insert @p value at @p key.
+ * @param [in] key A pointer to the key in @p map in which to insert @p value.
+ * @param [in] value A pointer to the the value to insert at @p key in @p map.
+ *
+ * @return
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ void *(*parcMap_Put)(PARCMap * map, void *key, void *value);
+
+ /**
+ * Copies all of the mappings from the specified map to this map (optional operation).
+ *
+ * @param [in,out] map The instance of `PARCMap` to be modified.
+ * @param [in] other The instance of `PARCMap` whose mappings should be copied to @p map.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ void (*parcMap_PutAll)(PARCMap *map, PARCMap *other);
+
+ /**
+ * Removes the mapping for a key from this map if it is present (optional operation).
+ *
+ * @param [in,out] map The instance of `PARCMap` to be modified.
+ * @param [in] key The key to the mapping to be removed
+ *
+ * @return
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ void *(*parcMap_Remove)(PARCMap * map, void *key);
+
+ /**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @param [in,out] map The instance of `PARCMap` to be inspected.
+ *
+ * @return int The number of mappings in the map
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ int (*parcMap_Size)(PARCMap *map);
+} PARCMapInterface;
+
+/**
+ * Create a PARCMap instance.
+ *
+ * Create an instance of `PARCMap` wrapping the given pointer to a base map
+ * interface and the {@ link PARCMapInterface} structure containing pointers
+ * to functions performing the actual Map operations.
+ *
+ * @param [in] map A pointer to the structure for the new instance of `PARCMap`
+ * @param [in] interface A pointer to the instance of `PARCMapInterface`
+ * @return A new instance of `PARCMap`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCMap *parcMap_Create(void *map, PARCMapInterface *interface);
+
+/**
+ * Removes all of the mappings from this map.
+ *
+ * The map will be empty after this call returns.
+ *
+ * @param [in,out] map A pointer to the instance of `PARCMap` to be cleared.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcMap_Clear(PARCMap *map);
+
+/**
+ * Returns true if this map contains a mapping for the specified key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ * @param [in] key A pointer to the key to be checked for in @p map
+ *
+ * @return True if the specified key is found in the map.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcMap_ContainsKey(PARCMap *map, void *key);
+
+/**
+ * Returns true if this map maps one or more keys to the specified value.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ * @param [in] value A pointer to the value to be checked for in @p map
+ *
+ * @return True if the specified value has one or more keys pointing to it.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcMap_ContainsValue(PARCMap *map, void *value);
+
+/**
+ * Determine if two `PARCMap` instances are equal.
+ *
+ * Two `PARCMap` instances are equal if, and only if, the maps have the same
+ * number of elements, all of the keys are equal and the values to which they point are equal
+ *
+ * The following equivalence relations on non-null `PARCMap` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCMap_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcMap_Equals(x, y)` must return true if and only if
+ * `parcMap_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcMap_Equals(x, y)` returns true and
+ * `parcMap_Equals(y, z)` returns true,
+ * then `parcMap_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcMap_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcMap_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] map A pointer to a `PARCMap` instance.
+ * @param [in] other A pointer to a `PARCMap` instance.
+ * @return true if the two `PARCMap` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMap *a = parcMap_Create();
+ * PARCMap *b = parcMap_Create();
+ *
+ * if (parcMap_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcMap_Equals(PARCMap *map, void *other);
+
+/**
+ * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ * @param [in] key A pointer to the key to be checked for which the value is to be returned.
+ *
+ * @return Null if no mapping for @p key exists
+ * @return Non Null A pointer to the value for @p key
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcMap_Get(PARCMap *map, void *key);
+
+/**
+ * Returns the hash code value for this map.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be hashed.
+ *
+ * @return The hash value for the @p map
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcMap_HashCode(PARCMap *map);
+
+/**
+ * Returns true if this map contains no key-value mappings.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ *
+ * @return True if the @p map is empty. else false.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcMap_IsEmpty(PARCMap *map);
+
+/**
+ * Associates the specified value with the specified key in this map (optional operation).
+ *
+ * @param [in,out] map A pointer to the instance of `PARCMap` into which the key,value pair should be inserted.
+ * @param [in] key A pointer to the key to be inserted in @p map
+ * @param [in] value A pointer to the value to be inserted in @p map at @p key
+ *
+ * @return The previous value at @p key if one exists, else NULL
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcMap_Put(PARCMap *map, void *key, void *value);
+
+/**
+ * Copies all of the mappings from the specified map to this map (optional operation).
+ *
+ * @param [in,out] map The map into which all the mappings from @p other should be copied.
+ * @param [in] other The instance of `PARCMap` whose mappings should be copied into @p map
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcMap_PutAll(PARCMap *map, PARCMap *other);
+
+/**
+ * Removes the mapping for a key from this map if it is present (optional operation).
+ *
+ *
+ * @param [in,out] map The instance of `PARCMap` in which @p key should be removed if present.
+ * @param [in] key The pointer to the key representing the mapping that should be removed from @p map.
+ *
+ * @return A pointer to the value previously mapped to @p key, if @p key exists.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcMap_Remove(PARCMap *map, void *key);
+
+/**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @param [in,out] map The instance of `PARCMap` to be measured
+ *
+ * @return The number of mappings in @p map.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcMap_Size(PARCMap *map);
+#endif // libparc_parc_Map_h
diff --git a/libparc/parc/algol/parc_Memory.c b/libparc/parc/algol/parc_Memory.c
new file mode 100755
index 00000000..e444baba
--- /dev/null
+++ b/libparc/parc/algol/parc_Memory.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+static const PARCMemoryInterface *parcMemory = &PARCStdlibMemoryAsPARCMemory;
+
+const PARCMemoryInterface *
+parcMemory_SetInterface(const PARCMemoryInterface *memoryProvider)
+{
+ assertFalse(memoryProvider == &PARCMemoryAsPARCMemory,
+ "You cannot use PARCMemoryAsPARCMemory as a memory provider for parcMemory.");
+ const PARCMemoryInterface *result = parcMemory;
+ parcMemory = memoryProvider;
+
+ return result;
+}
+
+size_t
+parcMemory_RoundUpToCacheLine(const size_t size)
+{
+ return parcMemory_RoundUpToMultiple(size, LEVEL1_DCACHE_LINESIZE);
+}
+
+size_t
+parcMemory_RoundUpToMultiple(const size_t size, const size_t multiple)
+{
+ if (size == 0) {
+ return multiple;
+ }
+
+ if (multiple == 0) {
+ return size;
+ }
+
+ size_t remainder = size % multiple;
+ if (remainder == 0) {
+ return size;
+ }
+ return size + multiple - remainder;
+}
+
+void *
+parcMemory_Allocate(const size_t size)
+{
+ return ((PARCMemoryAllocate *) parcMemory->Allocate)(size);
+}
+
+void *
+parcMemory_AllocateAndClear(const size_t size)
+{
+ return ((PARCMemoryAllocateAndClear *) parcMemory->AllocateAndClear)(size);
+}
+
+int
+parcMemory_MemAlign(void **pointer, const size_t alignment, const size_t size)
+{
+ return ((PARCMemoryMemAlign *) parcMemory->MemAlign)(pointer, alignment, size);
+}
+
+void
+parcMemory_DeallocateImpl(void **pointer)
+{
+ ((PARCMemoryDeallocate *) parcMemory->Deallocate)(pointer);
+}
+
+void *
+parcMemory_Reallocate(void *pointer, size_t newSize)
+{
+ return ((PARCMemoryReallocate *) parcMemory->Reallocate)(pointer, newSize);
+}
+
+char *
+parcMemory_StringDuplicate(const char *string, const size_t length)
+{
+ return ((PARCMemoryStringDuplicate *) parcMemory->StringDuplicate)(string, length);
+}
+
+uint32_t
+parcMemory_Outstanding(void)
+{
+ return ((PARCMemoryOutstanding *) parcMemory->Outstanding)();
+}
+
+char *
+parcMemory_Format(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ va_list copy;
+ va_copy(copy, ap);
+ int length = vsnprintf(NULL, 0, format, copy);
+ va_end(copy);
+
+ char *result = NULL;
+ if (length >= 0) {
+ result = parcMemory_Allocate(length + 1);
+
+ if (result != NULL) {
+ vsprintf(result, format, ap);
+ }
+ }
+ return result;
+}
+
+PARCMemoryInterface PARCMemoryAsPARCMemory = {
+ .Allocate = (uintptr_t) parcMemory_Allocate,
+ .AllocateAndClear = (uintptr_t) parcMemory_AllocateAndClear,
+ .MemAlign = (uintptr_t) parcMemory_MemAlign,
+ .Deallocate = (uintptr_t) parcMemory_DeallocateImpl,
+ .Reallocate = (uintptr_t) parcMemory_Reallocate,
+ .StringDuplicate = (uintptr_t) parcMemory_StringDuplicate,
+ .Outstanding = (uintptr_t) parcMemory_Outstanding
+};
diff --git a/libparc/parc/algol/parc_Memory.h b/libparc/parc/algol/parc_Memory.h
new file mode 100644
index 00000000..fe3c4b5a
--- /dev/null
+++ b/libparc/parc/algol/parc_Memory.h
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Memory.h
+ * @ingroup memory
+ * @brief A Facade to memory allocation features.
+ *
+ * PARC Memory provides an interface implementing many regularly available memory allocation functions.
+ * This interface is a Facade that software implementors may use to substitute different kinds of underlying
+ * Interfaces of these allocation fucntions.
+ * Notable examples are PARC Safe Memory and PARC Stdlib Memory.
+ *
+ */
+#ifndef libparc_parc_Memory_h
+#define libparc_parc_Memory_h
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/**
+ * @typedef PARCMemoryAllocate
+ * @brief Function signature for memory allocator.
+ *
+ */
+typedef void *(PARCMemoryAllocate)(size_t size);
+
+typedef void *(PARCMemoryAllocateAndClear)(size_t size);
+
+typedef int (PARCMemoryMemAlign)(void **pointer, size_t alignment, size_t size);
+
+typedef void (PARCMemoryDeallocate)(void **pointer);
+
+typedef void *(PARCMemoryReallocate)(void *pointer, size_t newSize);
+
+typedef char *(PARCMemoryStringDuplicate)(const char *string, size_t length);
+
+typedef uint32_t (PARCMemoryOutstanding)(void);
+
+/**
+ * @typedef PARCMemoryInterface
+ * @brief A structure containing pointers to functions that implement a PARC Memory manager.
+ *
+ * A 'PARC Memory' manager is a collection of inter-dependant functions that perform memory allocation,
+ * re-allocation, deallocation, and housekeeping.
+ *
+ * PARC Memory managers are cascadable, where one Interface may call other Interface in a chain.
+ * This permits the design and Interface of PARC Memory managers that specialise in fixed length memory sizes,
+ * reference counting, debugging and so forth.
+ */
+typedef struct parc_memory_interface {
+ /**
+ * A pointer to a function that allocates @p size bytes of memory
+ * and returns the allocation in the return value.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer indicating the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * @see AllocateAndClear
+ * @see Reallocate
+ */
+ uintptr_t Allocate;
+
+ /**
+ * Performs the same operation as `Allocate` and then sets each byte of the allocated memory to zero.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer indicating the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * @see Allocate
+ * @see Reallocate
+ */
+ uintptr_t AllocateAndClear;
+
+ /**
+ * A pointer to a function that allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * @see posix_memalign
+ */
+ uintptr_t MemAlign;
+
+ /**
+ * Deallocate memory previously allocated via `Allocate` or `AllocateAndClear`.
+ *
+ * @param [in,out] pointer A pointer to a `void *` pointer to the address of the allocated memory that will be set to zero.
+ *
+ * @see AllocateAndClear
+ * @see Allocate
+ * @see Reallocate
+ */
+ uintptr_t Deallocate;
+
+ /**
+ * Try to change the size of the allocation pointed to by @p pointer to @p newSize, and returns ptr.
+ * If there is not enough room to enlarge the memory allocation pointed to by @p pointer,
+ * create a new allocation,
+ * copy as much of the old data pointed to by @p pointer as will fit to the new allocation,
+ * deallocate the old allocation,
+ * and return a pointer to the allocated memory.
+ *
+ * If @p pointer is `NULL`,
+ * simply invoke the `Allocate` function to allocate memory aligned to the value of `sizeof(void *)` of @p newSize bytes.
+ * If @p newSize is zero and @p pointer is not NULL,
+ * a new, minimum sized object is allocated and the original object is freed.
+ *
+ * When extending a region previously allocated with `AllocateAndClear`,
+ * the additional memory is not guaranteed to be zero-filled.
+ *
+ * @param [in] pointer A pointer to previously allocated memory, or NULL.
+ * @param [in] newSize The size of the allocated memory.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * @see Deallocate
+ * @see AllocateAndClear
+ * @see Allocate
+ */
+ uintptr_t Reallocate;
+
+ /**
+ * Allocate sufficient memory for a copy of the string @p string,
+ * copy at most n characters from the string @p string into the allocated memory,
+ * and return the pointer to allocated memory.
+ *
+ * The copied string is always null-terminated.
+ *
+ * @param [in] string A pointer to a null-terminated string.
+ * @param [length] The maximum allows length of the resulting copy.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ */
+ uintptr_t StringDuplicate;
+
+ /**
+ * Return the number of allocations outstanding. That is, the numbe of allocations
+ * that have been made, but not yet freed.
+ *
+ * @return The number of outstanding allocations known to this `PARCMemoryInterface`.
+ */
+ uintptr_t Outstanding;
+} PARCMemoryInterface;
+
+/**
+ *
+ */
+extern PARCMemoryInterface PARCMemoryAsPARCMemory;
+
+/**
+ * Set the current memory allocation interface.
+ *
+ * The previous interface is returned.
+ *
+ * @param [in] memoryProvider A pointer to a {@link PARCMemoryInterface} instance.
+ *
+ * @return A pointer to the previous `PARCMemoryInterface` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMemoryInterface *previousInterface = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @see PARCSafeMemoryAsPARCMemory
+ * @see PARCMemoryAsPARCMemory
+ * @see PARCStdlibMemoryAsPARCMemory
+ */
+const PARCMemoryInterface *parcMemory_SetInterface(const PARCMemoryInterface *memoryProvider);
+
+/**
+ * Allocate memory.
+ *
+ * Allocates @p size bytes of memory and returns the allocation in the return value.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer set to the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocateMemory = parcMemory_Allocate(100);
+ * if (allocatedMemory == NULL) {
+ * // allocation failed.
+ * }
+ * }
+ * @endcode
+ */
+void *parcMemory_Allocate(const size_t size);
+
+/**
+ * Performs the same operation as `Allocate` and then sets each byte of the allocated memory to zero.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer set to the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocatedMemory = parcMemory_AllocateAndClear(100);
+ * if (allocatedMemory == NULL)
+ * // allocation failed
+ * }
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Allocate
+ */
+void *parcMemory_AllocateAndClear(const size_t size);
+
+/**
+ * Allocate aligned memory.
+ *
+ * Allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * int failure = parcMemory_MemAlign(&allocatedMemory, sizeof(void *), 100);
+ * if (failure == 0) {
+ * parcMemory_Deallocate(&allocatedMemory);
+ * // allocatedMemory is now equal to zero.
+ * }
+ * }
+ * @endcode
+ * @see `posix_memalign`
+ */
+int parcMemory_MemAlign(void **pointer, const size_t alignment, const size_t size);
+
+/**
+ * Deallocate memory previously allocated via `Allocate` or `AllocateAndClear`.
+ *
+ * @param [in,out] pointer A pointer to a `void *` pointer to the address of the allocated memory that will be set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocatedMemory = parcMemory_Allocate(100);
+ * if (allocatedMemory == NULL) {
+ * // allocation failed
+ * }
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Allocate
+ * @see parcMemory_AllocateAndClear
+ */
+void parcMemory_DeallocateImpl(void **pointer);
+
+#define parcMemory_Deallocate(_pointer_) parcMemory_DeallocateImpl((void **) _pointer_)
+
+/**
+ * Try to change the size of the allocation pointed to by @p pointer to @p newSize, and returns ptr.
+ * If there is not enough room to enlarge the memory allocation pointed to by @p pointer,
+ * create a new allocation,
+ * copy as much of the old data pointed to by @p pointer as will fit to the new allocation,
+ * deallocate the old allocation,
+ * and return a pointer to the allocated memory.
+ *
+ * If @p pointer is `NULL`,
+ * simply invoke the {@link parcMemory_Allocate} function to allocate memory aligned to the value of `sizeof(void *)` of @p newSize bytes.
+ * If @p newSize is zero and @p pointer is not NULL,
+ * a new, minimum sized object is allocated and the original object is freed.
+ *
+ * When extending a region previously allocated with `AllocateAndClear`,
+ * the additional memory is not guaranteed to be zero-filled.
+ *
+ * @param [in] pointer A pointer to previously allocated memory, or NULL.
+ * @param [in] newSize The size of the allocated memory.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocateMemory = parcMemory_Allocate(100);
+ *
+ * allocatedMemory = parcMemory_Reallocate(allocatedMemory, sizeof(void *), 200);
+ *
+ * parcMemory_Deallocate(&allocatedMemory);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Deallocate
+ * @see parcMemory_Allocate
+ */
+void *parcMemory_Reallocate(void *pointer, size_t newSize);
+
+/**
+ * Allocate sufficient memory for a copy of the string @p string,
+ * copy at most n characters from the string @p string into the allocated memory,
+ * and return the pointer to allocated memory.
+ *
+ * The copied string is always null-terminated.
+ *
+ * @param [in] string A pointer to a null-terminated string.
+ * @param [in] length The maximum allowed length of the resulting copy.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = "this is a string";
+ * char *copy = parcMemory_StringDuplicate(string, strlen(string));
+ *
+ * if (copy != NULL) {
+ * . . .
+ * parcMemory_Deallocate(&copy);
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link parcMemory_Deallocate()}
+ */
+char *parcMemory_StringDuplicate(const char *string, const size_t length);
+
+/**
+ * Return the number of outstanding allocations managed by this allocator.
+ *
+ * When you allocate memory, this count goes up by one. When you deallocate, it goes down by one.
+ * A well-behaved program will terminate with a call to parcMemory_Outstanding() returning 0.
+ *
+ * @return The number of memory allocations still outstanding (remaining to be deallocated).
+ *
+ * Example:
+ * @code
+ * {
+ * uint32_t numberOfAllocations = parcMemory_Outstanding();
+ * }
+ * @endcode
+ */
+uint32_t parcMemory_Outstanding(void);
+
+/**
+ * Round up a given number of bytes to be a multiple of the cache line size on the target computer.
+ *
+ * @param [in] size The number of bytes to round up.
+ *
+ * @return The number of bytes that are a multiple of the cache line size on the target computer.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = parcMemory_RoundUpToCacheLine(14);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_RoundUpToMultiple
+ */
+size_t parcMemory_RoundUpToCacheLine(const size_t size);
+
+/**
+ * Round up a given number of bytes to be an even multiple.
+ *
+ * @param [in] size The number of bytes to round up.
+ * @param [in] multiple The number of bytes to round up.
+ *
+ * @return The number of bytes that are an even multiple of @p multiple.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = parcMemory_RoundUp(14, 20);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_RoundUpToCacheLine
+ */
+size_t parcMemory_RoundUpToMultiple(size_t size, size_t multiple);
+
+/**
+ * @def parcMemory_SafeFree
+ *
+ * Free only non-null pointers to memory
+ *
+ * @param memory A pointer to allocated memory
+ *
+ */
+#define parcMemory_SafeFree(memory) do { if (memory != NULL) { parcMemory_Deallocate(& (memory)); } } while (0)
+
+/**
+ * Allocate a printf(3) style formatted string.
+ * The result must be deallocated via `parcMemory_Deallocate`
+ *
+ * This function is equivalent to the `asprintf(3)` function in the standard library.
+ *
+ * @param [in] format A pointer to nul-terminated C string containing a printf style format specification.
+ *
+ * @return non-NULL A pointer to allocated memory containing the formatted string.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = parcMemory_Format("Hello %s", "World");
+ *
+ * parcMemory_Deallocated(&string);
+ * }
+ * @endcode
+ */
+char *parcMemory_Format(const char *format, ...);
+#endif // libparc_parc_Memory_h
diff --git a/libparc/parc/algol/parc_Network.c b/libparc/parc/algol/parc_Network.c
new file mode 100644
index 00000000..35279648
--- /dev/null
+++ b/libparc/parc/algol/parc_Network.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <sys/socket.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+#include <parc/algol/parc_Network.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_URI.h>
+
+struct sockaddr *
+parcNetwork_SockAddress(const char *address, in_port_t port)
+{
+ // this is the final return value from the function
+ struct sockaddr *addr = NULL;
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ // getaddrinfo allocates this pointer
+ struct addrinfo *ai;
+ int failure = getaddrinfo(address, NULL, &hints, &ai);
+ if (failure == 0) {
+ switch (ai->ai_family) {
+ case PF_INET: {
+ struct sockaddr_in *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in));
+ if (result != NULL) {
+ assertTrue(ai->ai_addrlen == sizeof(struct sockaddr_in),
+ "Sockaddr wrong length, expected %zu got %u", sizeof(struct sockaddr_in), ai->ai_addrlen);
+ memcpy(result, ai->ai_addr, ai->ai_addrlen);
+ result->sin_port = htons(port);
+ addr = (struct sockaddr *) result;
+ }
+ break;
+ }
+
+ case PF_INET6: {
+ struct sockaddr_in6 *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in6));
+ if (result != NULL) {
+ assertTrue(ai->ai_addrlen == sizeof(struct sockaddr_in6),
+ "Sockaddr wrong length, expected %zu got %u", sizeof(struct sockaddr_in6), ai->ai_addrlen);
+
+ memcpy(result, ai->ai_addr, ai->ai_addrlen);
+ result->sin6_port = htons(port);
+ result->sin6_flowinfo = 0;
+ result->sin6_scope_id = 0;
+ addr = (struct sockaddr *) result;
+ }
+ break;
+ }
+
+ default: {
+ // unsupported protocol
+ addr = NULL;
+ break;
+ }
+ }
+
+ freeaddrinfo(ai);
+ }
+
+ return addr;
+}
+
+struct sockaddr_in *
+parcNetwork_SockInet4Address(const char *address, in_port_t port)
+{
+ struct sockaddr_in *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in));
+ if (result != NULL) {
+ result->sin_family = AF_INET;
+ result->sin_port = htons(port);
+#if defined(SIN6_LEN)
+ result->sin_len = sizeof(struct sockaddr_in);
+#endif
+ if (inet_pton(AF_INET, address, &(result->sin_addr)) == 1) {
+ return result;
+ }
+ parcMemory_Deallocate((void **) &result);
+ }
+
+ return NULL;
+}
+
+struct sockaddr_in6 *
+parcNetwork_SockInet6Address(const char *address, in_port_t port, uint32_t flowInfo, uint32_t scopeId)
+{
+ struct sockaddr_in6 *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in6));
+ if (result != NULL) {
+ result->sin6_family = AF_INET6;
+ result->sin6_port = htons(port);
+ result->sin6_flowinfo = flowInfo;
+ result->sin6_scope_id = scopeId;
+#if defined(SIN6_LEN)
+ result->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+
+ if (inet_pton(AF_INET6, address, &(result->sin6_addr)) == 1) {
+ return result;
+ }
+ parcMemory_Deallocate((void **) &result);
+ }
+
+ return NULL;
+}
+
+struct sockaddr_in *
+parcNetwork_SockInet4AddressAny()
+{
+ struct sockaddr_in *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in));
+ if (result != NULL) {
+ result->sin_family = AF_INET;
+ result->sin_addr.s_addr = INADDR_ANY;
+#if defined(SIN6_LEN)
+ result->sin_len = sizeof(struct sockaddr_in);
+#endif
+ return result;
+ }
+ return NULL;
+}
+
+PARCBufferComposer *
+parcNetwork_SockInet4Address_BuildString(const struct sockaddr_in *address, PARCBufferComposer *composer)
+{
+ assertNotNull(address, "Parameter must be a non-null pointer to a struct sockaddr_in.");
+
+ if (address->sin_family != AF_INET) {
+ trapIllegalValue(address->sin_family, "Expected an AF_INET configured address, not %d", address->sin_family);
+ }
+
+ char buffer[INET_ADDRSTRLEN];
+ inet_ntop(address->sin_family, &address->sin_addr, buffer, INET_ADDRSTRLEN);
+ parcBufferComposer_Format(composer, "inet4://%s:%u", buffer, ntohs(address->sin_port));
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcNetwork_SockInet6Address_BuildString(const struct sockaddr_in6 *address, PARCBufferComposer *composer)
+{
+ assertNotNull(address, "Parameter must be a non-null pointer to a struct sockaddr_in.");
+
+ if (address->sin6_family != AF_INET6) {
+ trapIllegalValue(address->sin_family, "Expected an AF_INET6 configured address, not %d", address->sin6_family);
+ }
+
+ char buffer[INET6_ADDRSTRLEN];
+ inet_ntop(address->sin6_family, &address->sin6_addr, buffer, INET6_ADDRSTRLEN);
+
+ parcBufferComposer_Format(composer, "inet6://[%s%%%u]:%u",
+ buffer,
+ address->sin6_scope_id,
+ ntohs(address->sin6_port));
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcNetwork_LinkAddress_BuildString(const unsigned char *address, size_t length, PARCBufferComposer *composer)
+{
+ parcBufferComposer_PutString(composer, "link://");
+ for (size_t i = 0; i < length; i++) {
+ if (i > 0) {
+ parcBufferComposer_PutString(composer, "-");
+ }
+ parcBufferComposer_Format(composer, "%02x", address[i]);
+ }
+ return composer;
+}
+
+struct sockaddr_in *
+parcNetwork_ParseInet4Address(const char *addressURI)
+{
+ struct sockaddr_in *result = NULL;
+
+ PARCURI *uri = parcURI_Parse(addressURI);
+ if (strcmp("inet4", parcURI_GetScheme(uri)) == 0) {
+ }
+ parcURI_Release(&uri);
+
+ return result;
+}
+
+static PARCBuffer *
+_parseMAC48AddressDashOrColon(const char *address, PARCBuffer *result)
+{
+ char *nextP = NULL;
+
+ const char *p = address;
+
+ int i = 0;
+ for (i = 0; i < 6; i++) {
+ long value = strtol(p, &nextP, 16);
+ if (nextP == p || (*nextP != ':' && *nextP != '-' && *nextP != 0)) {
+ result = NULL;
+ break;
+ }
+ parcBuffer_PutUint8(result, (uint8_t) value);
+
+ p = nextP + 1;
+ }
+
+ if (i != 6) {
+ result = NULL;
+ }
+
+ return result;
+}
+
+static PARCBuffer *
+_parseMAC48AddressDot(const char *address, PARCBuffer *result)
+{
+ char *nextP = NULL;
+
+ const char *p = address;
+
+ int i = 0;
+ for (i = 0; i < 3; i++) {
+ long value = strtol(p, &nextP, 16);
+ if (nextP == p || (*nextP != '.' && *nextP != 0)) {
+ result = NULL;
+ break;
+ }
+ parcBuffer_PutUint16(result, (uint16_t) value);
+
+ p = nextP + 1;
+ }
+
+ if (i != 3) {
+ result = NULL;
+ }
+
+ return result;
+}
+
+bool
+parcNetwork_ParseMAC48Address(const char *address, PARCBuffer *buffer)
+{
+ bool result = false;
+
+ size_t originalPosition = parcBuffer_Position(buffer);
+
+ if (strchr(address, '-') != NULL || strchr(address, ':') != NULL) {
+ if (_parseMAC48AddressDashOrColon(address, buffer) != NULL) {
+ result = true;
+ }
+ }
+
+ if (strchr(address, '.') != NULL) {
+ if (_parseMAC48AddressDot(address, buffer) != NULL) {
+ result = true;
+ }
+ ;
+ }
+
+ if (result == false) {
+ parcBuffer_SetPosition(buffer, originalPosition);
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcNetwork_ParseLinkAddress(const char *address)
+{
+ if (strncmp("link://", address, 7) == 0) {
+ PARCBuffer *result = parcBuffer_Allocate(7);
+
+ if (parcNetwork_ParseMAC48Address(&address[7], result) == false) {
+ parcBuffer_Release(&result);
+ trapIllegalValue(address, "Syntax error '%s'", address);
+ }
+
+ return parcBuffer_Flip(result);
+ }
+
+ trapIllegalValue(address, "Bad scheme '%s'", address);
+}
+
+bool
+parcNetwork_Inet4Equals(const struct sockaddr_in *x, const struct sockaddr_in *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ if (x->sin_family == y->sin_family) {
+ if (x->sin_addr.s_addr == y->sin_addr.s_addr) {
+ if (x->sin_port == y->sin_port) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Returns true for ::1 address, false otherwise
+ *
+ * The address is in network byte order
+ *
+ * @return true The address is local
+ * @return false The address is not local
+ */
+static bool
+_isInet6Loopback(struct sockaddr_in6 *sin6)
+{
+ if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Returns true if the address is on the 127.0.0.0/8 network
+ *
+ * The address is expected to be in network byte order
+ *
+ * @param [in] sin4 A pointer to a sockaddr_in containing an IPv4 address.
+ *
+ * @return true Address on 127.0.0.0/8
+ * @return false Not a 127.0.0.0/8
+ */
+static bool
+_isInet4Loopback(struct sockaddr_in *sin4)
+{
+ uint32_t hostorder = htonl(sin4->sin_addr.s_addr);
+ if ((hostorder & 0xFF000000) == 0x7F000000) {
+ return true;
+ }
+ return false;
+}
+
+bool
+parcNetwork_IsSocketLocal(struct sockaddr *sock)
+{
+ assertNotNull(sock, "Parameter sock must be non-null");
+ bool isLocal = false;
+
+ switch (sock->sa_family) {
+ case PF_LOCAL:
+ isLocal = true;
+ break;
+
+ case PF_INET:
+ isLocal = _isInet4Loopback((struct sockaddr_in *) sock);
+ break;
+
+ case PF_INET6:
+ isLocal = _isInet6Loopback((struct sockaddr_in6 *) sock);
+ break;
+
+ default:
+ break;
+ }
+
+ return isLocal;
+}
diff --git a/libparc/parc/algol/parc_Network.h b/libparc/parc/algol/parc_Network.h
new file mode 100644
index 00000000..efd5e632
--- /dev/null
+++ b/libparc/parc/algol/parc_Network.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Network.h
+ * @ingroup networking
+ * @brief Basic Networking Support
+ *
+ */
+#ifndef libparc_parc_Networking_h
+#define libparc_parc_Networking_h
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+
+#ifndef INPORT_ANY
+#define INPORT_ANY 0
+#endif
+
+#ifdef __ANDROID__
+typedef uint16_t in_port_t;
+#endif
+
+/**
+ * Parses any string in to an address, if possible
+ *
+ * The string may be an IPv6, IPv6 or hostname. If the string does not match an IPv4 or IPv6 nominal format,
+ * it will try to resolve the string as a hostname. If that fails, the function will return NULL.
+ *
+ * IMPORTANT: the returned pointer is allocated with <code>parcMemory_Allocate()</code> and you must use <code>parcMemory_Deallocate()</code>.
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in] port the port address
+ *
+ * @return NULL Could not parse the address or resolve as a hostname
+ * @return non-NULL a valid sockaddr. You shoule examine `sockaddr->sa_family` to determine IPv4 or IPv6.
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr *addr;
+ * addr = parcNetwork_SockAddress("1.2.3.4", 555);
+ * assertTrue(addr && addr->sa_family == AF_INET, "Addr not IPv4 for a dotted quad.");
+ * struct sockaddr_in *addr_in = (struct sockaddr_in *) addr;
+ * // ...
+ * parcMemory_Deallocate((void **)&addr);
+ *
+ * addr = parcNetwork_SockAddress("fe80::aa20:66ff:fe00:314a", 555);
+ * assertTrue(addr && addr->sa_family == AF_INET6, "Addr not IPv6.");
+ * struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) addr;
+ * // ...
+ * parcMemory_Deallocate((void **)&addr);
+ *
+ * addr = parcNetwork_SockAddress("alpha.parc.com", 555);
+ * assertTrue(addr && addr->sa_family == AF_INET, "Addr not IPv4 hostname with only ipv4 address.");
+ * // ...
+ * parcMemory_Deallocate((void **)&addr);
+ *
+ * addr = parcNetwork_SockAddress("Over the rainbow, way up high", 555);
+ * assertNull(addr, "Addr no null for bogus name.");
+ *
+ * }
+ * @endcode
+ */
+struct sockaddr *parcNetwork_SockAddress(const char *address, in_port_t port);
+
+/**
+ * Compose an allocated sockaddr_in structure.
+ *
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in] port the port address
+ * @return A pointer to an allocated struct sockaddr_in which must be freed by <code>parcMemory_Deallocate()</code>, or NULL on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in *parcNetwork_SockInet4Address(const char *address, in_port_t port);
+
+/**
+ * Compose an allocated sockaddr_in6 structure.
+ *
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in] port the port address
+ * @param flowInfo
+ * @param scopeId
+ * @return A pointer to an allocated sockaddr_in6 structure that must be freed via parcMemory_Deallocate(), or NULL on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in6 *parcNetwork_SockInet6Address(const char *address, in_port_t port, uint32_t flowInfo, uint32_t scopeId);
+
+/**
+ * Allocate a struct sockaddr_in
+ *
+ * @return A pointer to an allocated struct sockaddr_in which must be freed by {@link parcMemory_Deallocate()}, or NULL on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in *parcNetwork_SockInet4AddressAny(void);
+
+/**
+ * Append the string representation of the `struct sockaddr_in` to a {@link PARCBufferComposer}.
+ *
+ * The position of the `PARCBufferComposer` is incremented by the number characters necessary to represent the `struct sockaddr_in`
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in,out] composer The instance of `PARCBufferComposer` to be modified.
+ * @return return
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcNetwork_SockInet4Address_BuildString(const struct sockaddr_in *address, PARCBufferComposer *composer);
+
+/**
+ * Append the string representation of the `struct sockaddr_in6` to a `PARCBufferComposer`.
+ *
+ * The position of the `PARCBufferComposer` is incremented by the number characters necessary to represent the `struct sockaddr_in6`
+ *
+ *
+ * @param [in] address A pointer to the spckaddr_in6 to append.
+ * @param [in,out] composer a POinter to the `PARCBufferComposer` to modify.
+ * @return A pointer to the @p composer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcNetwork_SockInet6Address_BuildString(const struct sockaddr_in6 *address, PARCBufferComposer *composer);
+
+/**
+ * The standard (IEEE 802) format for printing MAC-48 addresses in human-friendly form is six groups of two hexadecimal digits,
+ * separated by hyphens (-) or colons (:), in transmission order (e.g. `01-23-45-67-89-ab` or `01:23:45:67:89:ab`).
+ * This form is also commonly used for EUI-64.
+ * Another convention used by networking equipment uses three groups of four hexadecimal digits separated by dots (.)
+ * (e.g. `0123.4567.89ab` ), again in transmission order.
+ *
+ * @param [in] address A pointer to the adress of the string.
+ * @param [in] length The size of the buffer
+ * @param [in] composer A pointer to the buffer.
+ * @return A pointer to the `PARCBufferComposer` containing the built string.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcNetwork_LinkAddress_BuildString(const unsigned char *address, size_t length, PARCBufferComposer *composer);
+
+/**
+ * Parse a link address, expressed as a nul-terminated C string of the form
+ * `link://` followed by hexadecimal numbers representing single byte values,
+ * each value separated by either a ':' or '-' character.
+ *
+ * The standard (IEEE 802) format for printing MAC-48 addresses in human-friendly form is six groups of two hexadecimal digits,
+ * separated by hyphens (-) or colons (:), in transmission order (e.g. `01-23-45-67-89-ab` or `01:23:45:67:89:ab`).
+ * This form is also commonly used for EUI-64.
+ *
+ * Another convention used by networking equipment uses three groups of four hexadecimal digits separated by dots (.)
+ * (e.g. `0123.4567.89ab` ), again in transmission order.
+ *
+ * @param address A null-terminated C string of the form `link://` followed single byte values separated by ':' or '-'.
+ * @return A PARCBuffer instance containing the parsed bytes of the link address.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBuffer *address = parcNetwork_ParseLinkAddress("link://32-00-14-06-30-60");
+ *
+ * }
+ * @endcode
+ *
+ * @see parcNetwork_ParseMAC48Address
+ */
+PARCBuffer *parcNetwork_ParseLinkAddress(const char *address);
+
+/**
+ * Parse a MAC-48 address, expressed as a nul-terminated C string of the standard (IEEE 802)
+ * format for printing MAC-48 addresses in human-friendly form is six groups of two hexadecimal digits,
+ * separated by hyphens (-) or colons (:), in transmission order (e.g. `01-23-45-67-89-ab` or `01:23:45:67:89:ab`).
+ * This form is also commonly used for EUI-64.
+ *
+ * Another convention used by networking equipment uses three groups of four hexadecimal digits separated by dots (.)
+ * (e.g. `0123.4567.89ab` ), again in transmission order.
+ *
+ * @param [in] address A null-terminated C string of the form `link://` followed single byte values separated by ':' or '-'.
+ * @param [out] result A pointer to a `PARCBuffer` for the result.
+ * @return `true` If the address was successfully parsed.
+ * @return `false` if the address was not successfully parsed. The output PARCBuffer is unmodified.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBuffer *address = parcNetwork_ParseMAC48Address("32-00-14-06-30-60");
+ *
+ * }
+ * @endcode
+ */
+bool parcNetwork_ParseMAC48Address(const char *address, PARCBuffer *result);
+
+/**
+ * Return the address parsed from @p addressURI.
+ *
+ * @param [in] addressURI
+ * @return A pointer to the `sockaddr_in`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in *parcNetwork_ParseInet4Address(const char *addressURI);
+
+/**
+ * Determines if a socket is local
+ *
+ * A socket is local if: (a) PF_LOCAL/AF_UNIX, or (b) PF_INET and on the 127.0.0.0/8 network,
+ * or (c) PF_INET6 and equal to the ::1 address. Anything else is considered non-local.
+ *
+ * @param [in] sock A socket structure
+ *
+ * @return `true` The socket represents a local/loopback address
+ * @return `false` The socket is not a local/loopback address
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900);
+ * assertTrue(parcNetwork_IsSocketLocal(s), "This will not assert");
+ * parcMemory_Deallocate((void **)&s);
+ * }
+ * @endcode
+ */
+bool parcNetwork_IsSocketLocal(struct sockaddr *sock);
+
+/**
+ * Return true if two `sockaddr_in` instances are equal.
+ *
+ * The equality function that this evaluates must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, parcNetwork_Inet4Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcNetwork_Inet4Equals(x, y) must return true if and only if
+ * parcNetwork_Inet4Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcNetwork_Inet4Equals(x, y) returns true and
+ * parcNetwork_Inet4Equals(y, z) returns true,
+ * then parcNetwork_Inet4Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcNetwork_Inet4Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] x A pointer to a struct sockaddr_in instance.
+ * @param [in] y A pointer to a struct sockaddr_in instance.s
+ * @return true the given sockaddr_in instances are equal.
+ * @return false the given sockaddr_in instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcNetwork_Inet4Equals(const struct sockaddr_in *x, const struct sockaddr_in *y);
+#endif // libparc_parc_Networking_h
diff --git a/libparc/parc/algol/parc_Object.c b/libparc/parc/algol/parc_Object.c
new file mode 100644
index 00000000..578f1e1a
--- /dev/null
+++ b/libparc/parc/algol/parc_Object.c
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/concurrent/parc_AtomicUint64.h>
+
+typedef struct parc_object_locking {
+ pthread_mutex_t lock;
+ pthread_cond_t notification;
+ pthread_t locker;
+} _PARCObjectLocking;
+
+/*
+ * This is the per-object header.
+ * The size of this structure must be less than or equal to the value used in the parcObject_PrefixLength macro.
+ */
+typedef struct object_header {
+#define PARCObject_HEADER_MAGIC_GUARD_NUMBER 0x0ddFadda
+ uint32_t magicGuardNumber;
+ bool isAllocated;
+ bool barrier;
+ PARCReferenceCount references;
+ const PARCObjectDescriptor *descriptor;
+
+ // The locking member points to the locking structure or is NULL if the object does not support locking.
+ _PARCObjectLocking *locking;
+
+ // Currently every object is lockable, but at some point in the future this will be controlled by the descriptor.
+ _PARCObjectLocking lock;
+
+ void *data[];
+} _PARCObjectHeader;
+
+/*
+ * Increment/decrement a pointer by the given value.
+ *
+ * @param [in] base The base pointer.
+ * @param [in] increment The value of the pointer increment.
+ *
+ * @return void* The updated pointer
+ */
+static inline void *
+_pointerAdd(const void *base, const size_t increment)
+{
+ void *result = (void *) &((char *) base)[increment];
+ return result;
+}
+
+/*
+ * Compute the size of the prefix as the number of bytes necessary
+ * to fit the object header (with padding), and any additional per-object data, into allocated memory,
+ * such that the first address after the header and any additional per-object data,
+ * is aligned according to the value of the alignment parameter.
+ *
+ * For example, if the object header is 5 bytes long, and the alignment is 4 (bytes),
+ * then the necessary number of bytes to fit the header
+ * (and yet maintain the proper alignment for the first memory location after the header) is 8.
+ *
+ * @param [in] alignment Cache alignment
+ *
+ * @return The size of the object header as the number of bytes necessary to fit the header (with padding) into allocated memory.
+ */
+static inline size_t
+_parcObject_PrefixLength(const PARCObjectDescriptor *descriptor)
+{
+ return parcObject_PrefixLength(descriptor->objectAlignment);
+}
+
+/*
+ * Given the memory address, return a pointer to the corresponding _PARCObjectHeader structure.
+ *
+ * @param [in] object The base pointer to the object.
+ *
+ * @return A _PARCObjectHeader struct encapsulating the object's header information.
+ */
+static inline _PARCObjectHeader *
+_parcObject_Header(const PARCObject *object)
+{
+ return _pointerAdd(object, -sizeof(_PARCObjectHeader));
+}
+
+static inline const PARCObjectDescriptor *
+_parcObject_Descriptor(const PARCObject *object)
+{
+ return (_parcObject_Header(object)->descriptor);
+}
+
+static inline _PARCObjectLocking *
+_parcObjectHeader_Locking(const PARCObject *object)
+{
+ return _parcObject_Header(object)->locking;
+}
+
+static inline bool
+_parcObjectHeader_IsValid(const _PARCObjectHeader *header, const PARCObject *object)
+{
+ bool result = true;
+
+ if ((intptr_t) header >= (intptr_t) object) {
+ result = false;
+ } else if (header->magicGuardNumber != PARCObject_HEADER_MAGIC_GUARD_NUMBER) {
+ result = false;
+ } else if (header->references == 0) {
+ result = false;
+ }
+
+ return result;
+}
+
+/*
+ * Compute the origin of the allocated memory.
+ *
+ * This will be greater than the start of the object header.
+ * due to alignment requirements causing the object header to be offset from the origin.
+ */
+static inline void *
+_parcObject_Origin(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ return _pointerAdd(object, -_parcObject_PrefixLength(header->descriptor));
+}
+
+static inline PARCObjectEquals *
+_parcObject_ResolveEquals(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->equals == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->equals;
+}
+
+static inline PARCObjectCopy *
+_parcObject_ResolveCopy(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->copy == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->copy;
+}
+
+static inline PARCObjectToString *
+_parcObject_ResolveToString(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->toString == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->toString;
+}
+
+static inline PARCObjectToJSON *
+_parcObject_ResolveToJSON(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->toJSON == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->toJSON;
+}
+
+static bool
+_parcObject_Destructor(const PARCObjectDescriptor *descriptor, PARCObject **object)
+{
+ if (descriptor != NULL) {
+ if (descriptor->destructor != NULL) {
+ return descriptor->destructor(object);
+ } else if (descriptor->destroy != NULL) {
+ descriptor->destroy(object);
+ }
+ }
+
+ return true;
+}
+
+static int
+_parcObject_Compare(const PARCObject *self, const PARCObject *other)
+{
+ _PARCObjectHeader *header = _parcObject_Header(self);
+ size_t length = header->descriptor->objectSize;
+ int result = memcmp(self, other, length);
+ return result;
+}
+
+static PARCObject *
+_parcObject_Copy(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ size_t length = header->descriptor->objectSize;
+
+ void *result = parcObject_CreateInstanceImpl(header->descriptor);
+ memcpy(result, object, length);
+ parcObject_OptionalAssertValid(result);
+ return result;
+}
+
+static bool
+_parcObject_Equals(const PARCObject *x, const PARCObject *y)
+{
+ _PARCObjectHeader *header = _parcObject_Header(x);
+
+ bool result = memcmp(x, y, header->descriptor->objectSize) == 0;
+
+ return result;
+}
+
+static char *
+_parcObject_ToString(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ char *string;
+ int nwritten = asprintf(&string,
+ "Object@%p { .references=%" PRId64 ", .objectLength = %zd, .objectAlignment=%u } data %p\n",
+ (void *) header,
+ header->references, header->descriptor->objectSize, header->descriptor->objectAlignment, object);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+static PARCJSON *
+_parcObject_ToJSON(const PARCObject *object)
+{
+ _PARCObjectHeader *prefix = _parcObject_Header(object);
+
+ PARCJSON *json = parcJSON_Create();
+
+ parcJSON_AddInteger(json, "references", prefix->references);
+ parcJSON_AddInteger(json, "objectLength", prefix->descriptor->objectSize);
+ parcJSON_AddInteger(json, "objectAlignment", prefix->descriptor->objectAlignment);
+
+ char *addressString;
+ int nwritten = asprintf(&addressString, "%p", object);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+
+ parcJSON_AddString(json, "address", addressString);
+
+ return json;
+}
+
+static PARCHashCode
+_parcObject_HashCode(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ return parcHashCode_Hash(object, header->descriptor->objectSize);
+}
+
+static void
+_parcObject_Display(const PARCObject *object, const int indentation)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ parcDisplayIndented_PrintLine(indentation, "PARCObject@%p @%p={ .name=%s .references=%zd }\n",
+ object, header, header->descriptor->name, header->references);
+}
+
+const PARCObjectDescriptor
+parcObject_DescriptorName(PARCObject) =
+{
+ .name = "PARCObject",
+ .destroy = NULL,
+ .destructor = NULL,
+ .release = NULL,
+ .copy = _parcObject_Copy,
+ .toString = _parcObject_ToString,
+ .equals = _parcObject_Equals,
+ .compare = _parcObject_Compare,
+ .hashCode = _parcObject_HashCode,
+ .toJSON = _parcObject_ToJSON,
+ .display = _parcObject_Display,
+ .super = NULL,
+ .isLockable = true,
+ .objectSize = 0,
+ .objectAlignment = sizeof(void *)
+};
+
+bool
+parcObject_IsValid(const PARCObject *object)
+{
+ bool result = true;
+
+ if (object == NULL) {
+ result = false;
+ } else {
+ if (_parcObjectHeader_IsValid(_parcObject_Header(object), object) == false) {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcObjectHeader_OptionalAssertValid(_instance_)
+#else
+# define parcObjectHeader_OptionalAssertValid(_instance_) _parcObjectHeader_AssertValid(_instance_)
+#endif
+
+static inline void
+_parcObjectHeader_AssertValid(const _PARCObjectHeader *header, const PARCObject *object)
+{
+ trapIllegalValueIf(header->magicGuardNumber != PARCObject_HEADER_MAGIC_GUARD_NUMBER, "PARCObject@%p is corrupt.", object);
+ trapIllegalValueIf(header->descriptor == NULL, "PARCObject@%p descriptor cannot be NULL.", object);
+ if (header->descriptor->isLockable) {
+ trapIllegalValueIf(header->locking == NULL, "PARCObject@%p is corrupt. Is Lockable but no locking structure", object);
+ }
+}
+
+static inline void
+_parcObject_AssertValid(const PARCObject *object)
+{
+ trapIllegalValueIf(object == NULL, "PARCObject must be a non-null pointer.");
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ _parcObjectHeader_AssertValid(header, object);
+}
+
+void
+parcObject_AssertValid(const PARCObject *object)
+{
+ _parcObject_AssertValid(object);
+}
+
+PARCObject *
+parcObject_Acquire(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ parcAtomicUint64_Increment(&header->references);
+
+ return (PARCObject *) object;
+}
+
+static inline PARCObjectCompare *
+_parcObject_ResolveCompare(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->compare == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->compare;
+}
+
+int
+parcObject_Compare(const PARCObject *x, const PARCObject *y)
+{
+ int result = 0;
+ if ((x == NULL) || (y == NULL)) {
+ result = 0;
+ if (x != NULL) {
+ result = 1;
+ } else if (y != NULL) {
+ result = -1;
+ }
+ return result;
+ }
+
+ parcObject_OptionalAssertValid(x);
+ parcObject_OptionalAssertValid(y);
+
+ PARCObjectCompare *compare = _parcObject_ResolveCompare(_parcObject_Descriptor(x));
+ result = compare(x, y);
+
+ return result;
+}
+
+bool
+parcObject_IsInstanceOf(const PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ bool result = false;
+
+ if (object != NULL) {
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ if (_parcObjectHeader_IsValid(header, object)) {
+ const PARCObjectDescriptor *d = _parcObject_Descriptor(object);
+
+ while (result == false) {
+ if (d == descriptor) {
+ result = true;
+ }
+ d = d->super;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_Equals(const PARCObject *x, const PARCObject *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x != NULL && y != NULL) {
+ _PARCObjectHeader *xHeader = _parcObject_Header(x);
+ _PARCObjectHeader *yHeader = _parcObject_Header(y);
+
+ if (xHeader->descriptor == yHeader->descriptor) {
+ PARCObjectEquals *equals = _parcObject_ResolveEquals(xHeader->descriptor);
+ result = equals(x, y);
+ }
+ }
+
+ return result;
+}
+
+static inline PARCObjectHashCode *
+_parcObject_ResolveHashCode(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->hashCode == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->hashCode;
+}
+
+PARCHashCode
+parcObject_HashCode(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectHashCode *hashCode = _parcObject_ResolveHashCode(_parcObject_Descriptor(object));
+
+ return hashCode(object);
+}
+
+static inline PARCObjectDisplay *
+_parcObject_ResolveDisplay(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->display == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->display;
+}
+
+void
+parcObject_Display(const PARCObject *object, const int indentation)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectDisplay *display = _parcObject_ResolveDisplay(_parcObject_Descriptor(object));
+
+ display(object, indentation);
+}
+
+char *
+parcObject_ToString(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectToString *toString = _parcObject_ResolveToString(_parcObject_Descriptor(object));
+
+ return toString(object);
+}
+
+PARCJSON *
+parcObject_ToJSON(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectToJSON *toJSON = _parcObject_ResolveToJSON(_parcObject_Descriptor(object));
+ return toJSON(object);
+}
+
+PARCObject *
+parcObject_CreateAndClearInstanceImpl(const PARCObjectDescriptor *descriptor)
+{
+ PARCObject *result = parcObject_CreateInstanceImpl(descriptor);
+ memset(result, 0, descriptor->objectSize);
+ return result;
+}
+
+static pthread_once_t _parcObject_GlobalLockAttributesInitialized = PTHREAD_ONCE_INIT;
+static pthread_mutexattr_t _parcObject_GlobalLockAttributes;
+
+static void
+_parcObject_InitializeGobalLockAttributes(void)
+{
+ pthread_mutexattr_init(&_parcObject_GlobalLockAttributes);
+ pthread_mutexattr_settype(&_parcObject_GlobalLockAttributes, PTHREAD_MUTEX_ERRORCHECK);
+}
+
+static inline void
+_parcObject_InitializeLocking(_PARCObjectLocking *locking)
+{
+ if (locking != NULL) {
+ pthread_once(&_parcObject_GlobalLockAttributesInitialized, _parcObject_InitializeGobalLockAttributes);
+
+ pthread_mutex_init(&locking->lock, &_parcObject_GlobalLockAttributes);
+ pthread_cond_init(&locking->notification, NULL);
+
+ locking->locker = (pthread_t) NULL;
+ }
+}
+
+static inline _PARCObjectHeader *
+_parcObjectHeader_InitAllocated(_PARCObjectHeader *header, const PARCObjectDescriptor *descriptor)
+{
+ header->magicGuardNumber = PARCObject_HEADER_MAGIC_GUARD_NUMBER;
+ header->barrier = false;
+ header->references = 1;
+ header->descriptor = (PARCObjectDescriptor *) descriptor;
+ header->isAllocated = true;
+
+ if (header->descriptor->isLockable) {
+ header->locking = &header->lock;
+ _parcObject_InitializeLocking(header->locking);
+ } else {
+ header->locking = NULL;
+ }
+
+ return header;
+}
+
+static inline _PARCObjectHeader *
+_parcObjectHeader_InitUnallocated(_PARCObjectHeader *header, const PARCObjectDescriptor *descriptor)
+{
+ _parcObjectHeader_InitAllocated(header, descriptor);
+ header->isAllocated = false;
+
+ return header;
+}
+
+PARCObject *
+parcObject_WrapImpl(void *memory, const PARCObjectDescriptor *descriptor)
+{
+ size_t prefixLength = _parcObject_PrefixLength(descriptor);
+ PARCObject *object = _pointerAdd(memory, prefixLength);
+
+ _parcObjectHeader_InitUnallocated(_parcObject_Header(object), descriptor);
+
+ return object;
+}
+
+PARCObject *
+parcObject_CreateInstanceImpl(const PARCObjectDescriptor *descriptor)
+{
+ size_t prefixLength = _parcObject_PrefixLength(descriptor);
+ size_t totalMemoryLength = prefixLength + descriptor->objectSize;
+
+ void *origin = NULL;
+ parcMemory_MemAlign(&origin, sizeof(void *), totalMemoryLength);
+
+ if (origin == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ PARCObject *object = _pointerAdd(origin, prefixLength);
+
+ _parcObjectHeader_InitAllocated(_parcObject_Header(object), descriptor);
+
+ errno = 0;
+ return object;
+}
+
+PARCObject *
+parcObject_InitInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ _parcObjectHeader_InitUnallocated(header, descriptor);
+ return object;
+}
+
+PARCObject *
+parcObject_InitAndClearInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ parcObject_InitInstanceImpl(object, descriptor);
+
+ memset(object, 0, descriptor->objectSize);
+ return object;
+}
+
+PARCObject *
+parcObject_Copy(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectCopy *copy = _parcObject_ResolveCopy(_parcObject_Descriptor(object));
+ return copy(object);
+}
+
+PARCReferenceCount
+parcObject_Release(PARCObject **objectPointer)
+{
+ PARCObject *object = *objectPointer;
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ trapIllegalValueIf(header->references == 0, "PARCObject@%p references must be > 0", object);
+
+ PARCReferenceCount result = parcAtomicUint64_Decrement(&header->references);
+
+ if (result == 0) {
+ if (_parcObject_Destructor(header->descriptor, objectPointer)) {
+ if (header->locking != NULL) {
+ pthread_cond_destroy(&header->locking->notification);
+ }
+ if (header->isAllocated) {
+ void *origin = _parcObject_Origin(object);
+ parcMemory_Deallocate(&origin);
+ }
+ assertNotNull(*objectPointer, "Class implementation unnecessarily clears the object pointer.");
+ } else {
+ assertNull(*objectPointer, "Class implementation must clear the object pointer.");
+ }
+ }
+
+ *objectPointer = NULL;
+ return result;
+}
+
+PARCReferenceCount
+parcObject_GetReferenceCount(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ return header->references;
+}
+
+const PARCObjectDescriptor *
+parcObject_GetDescriptor(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ return header->descriptor;
+}
+
+const PARCObjectDescriptor *
+parcObject_SetDescriptor(PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ parcObject_OptionalAssertValid(object);
+ assertNotNull(descriptor, "PARCObjectDescriptor cannot be NULL.");
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ const PARCObjectDescriptor *result = header->descriptor;
+ header->descriptor = (PARCObjectDescriptor *) descriptor;
+
+ return result;
+}
+
+PARCObjectDescriptor *
+parcObjectDescriptor_Create(const char *name,
+ size_t objectSize,
+ unsigned int objectAlignment,
+ bool isLockable,
+ PARCObjectDestructor *destructor,
+ PARCObjectRelease *release,
+ PARCObjectCopy *copy,
+ PARCObjectToString *toString,
+ PARCObjectEquals *equals,
+ PARCObjectCompare *compare,
+ PARCObjectHashCode *hashCode,
+ PARCObjectToJSON *toJSON,
+ PARCObjectDisplay *display,
+ const PARCObjectDescriptor *superType,
+ PARCObjectTypeState *typeState)
+{
+ assertNotNull(superType, "Supertype descriptor cannot be NULL.");
+
+ PARCObjectDescriptor *result = parcMemory_AllocateAndClear(sizeof(PARCObjectDescriptor));
+ if (result != NULL) {
+ strncpy(result->name, name, sizeof(result->name) - 1);
+ result->name[sizeof(result->name) - 1] = 0;
+ result->destroy = NULL;
+ result->destructor = destructor;
+ result->release = release;
+ result->copy = copy;
+ result->toString = toString;
+ result->equals = equals;
+ result->compare = compare;
+ result->hashCode = hashCode;
+ result->toJSON = toJSON;
+ result->display = display;
+ result->super = superType;
+ result->objectSize = objectSize;
+ result->objectAlignment = objectAlignment;
+ result->typeState = typeState;
+ result->isLockable = isLockable;
+ }
+ return result;
+}
+
+PARCObjectDescriptor *
+parcObjectDescriptor_CreateExtension(const PARCObjectDescriptor *superType, const char *name)
+{
+ PARCObjectDescriptor *result = parcMemory_AllocateAndClear(sizeof(PARCObjectDescriptor));
+ *result = *superType;
+ strncpy(result->name, name, sizeof(result->name) - 1);
+ result->name[sizeof(result->name) - 1] = 0;
+ return result;
+}
+
+PARCObjectTypeState *
+parcObjectDescriptor_GetTypeState(const PARCObjectDescriptor *descriptor)
+{
+ return descriptor->typeState;
+}
+
+const PARCObjectDescriptor *
+parcObjectDescriptor_GetSuperType(const PARCObjectDescriptor *descriptor)
+{
+ return descriptor->super;
+}
+
+bool
+parcObjectDescriptor_Destroy(PARCObjectDescriptor **descriptorPointer)
+{
+ parcMemory_Deallocate(descriptorPointer);
+ return true;
+}
+
+bool
+parcObject_Unlock(const PARCObject *object)
+{
+ bool result = false;
+
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ if (header->references > 0) {
+ _parcObjectHeader_AssertValid(header, object);
+
+ if (object != NULL) {
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ locking->locker = (pthread_t) NULL;
+ result = (pthread_mutex_unlock(&locking->lock) == 0);
+
+ assertTrue(result, "Attempted to unlock an unowned lock.");
+ }
+ }
+ }
+ return result;
+}
+
+bool
+parcObject_Lock(const PARCObject *object)
+{
+#ifndef __ANDROID__
+ extern int errno;
+#endif
+ bool result = false;
+
+ parcObject_OptionalAssertValid(object);
+
+ if (object != NULL) {
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ trapCannotObtainLockIf(pthread_equal(locking->locker, pthread_self()),
+ "Recursive locks on %p are not supported.", object);
+
+ errno = pthread_mutex_lock(&locking->lock);
+
+ if (errno == 0) {
+ locking->locker = pthread_self();
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_TryLock(const PARCObject *object)
+{
+ bool result = false;
+
+ if (object != NULL) {
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ trapCannotObtainLockIf(pthread_equal(locking->locker, pthread_self()), "Recursive locks are not supported.");
+
+ int lockStatus = pthread_mutex_trylock(&locking->lock);
+
+ if (lockStatus == 0) {
+ result = true;
+ locking->locker = pthread_self();
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_IsLocked(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+ bool result = false;
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ result = locking->locker != (pthread_t) NULL;
+ }
+
+ return result;
+}
+
+void
+parcObject_Wait(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ pthread_cond_wait(&locking->notification, &locking->lock);
+ }
+}
+
+bool
+parcObject_WaitUntil(const PARCObject *object, const struct timespec *time)
+{
+ parcObject_OptionalAssertValid(object);
+
+ bool result = false;
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ int waitResult = pthread_cond_timedwait(&locking->notification, &locking->lock, time);
+ if (waitResult == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_WaitFor(const PARCObject *object, const uint64_t nanoSeconds)
+{
+ parcObject_OptionalAssertValid(object);
+
+ bool result = false;
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ // Convert timeval to timespec.
+ struct timespec time = {
+ .tv_sec = now.tv_sec,
+ .tv_nsec = (now.tv_usec * 1000)
+ };
+ time.tv_nsec += nanoSeconds;
+ time.tv_sec += time.tv_nsec / 1000000000;
+ time.tv_nsec = time.tv_nsec % 1000000000;
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ int waitResult = pthread_cond_timedwait(&locking->notification, &locking->lock, &time);
+
+ if (waitResult == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcObject_Notify(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ pthread_cond_signal(&locking->notification);
+ }
+}
+
+void
+parcObject_NotifyAll(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ pthread_cond_broadcast(&locking->notification);
+ }
+}
+
+bool
+parcObject_BarrierSet(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ while (__sync_bool_compare_and_swap(&header->barrier, false, true) == false) {
+ ;
+ }
+ return true;
+}
+
+bool
+parcObject_BarrierUnset(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ while (__sync_bool_compare_and_swap(&header->barrier, true, false) == false) {
+ ;
+ }
+
+ return false;
+}
diff --git a/libparc/parc/algol/parc_Object.h b/libparc/parc/algol/parc_Object.h
new file mode 100644
index 00000000..0f3a932b
--- /dev/null
+++ b/libparc/parc/algol/parc_Object.h
@@ -0,0 +1,1504 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Object.h
+ * @ingroup memory
+ * @brief Reference Counted Object Memory
+ *
+ * An arbitrary C structure stored in allocated memory with a reference counter.
+ *
+ * When a PARC Object is created, via `parcObject_Create`, or `parcObject_Copy` it has reference count of 1.
+ *
+ * References to a PARC Object are acquired by calling `parcObject_Acquire`
+ * and once a reference is no longer needed it is released via parcObject_Release`.
+ * When the last reference is released, the memory storing the PARC Object is deallocated.
+ * Any further reference to that object or its memory is undefined.
+ *
+ * When creating a PARCObject, the caller may supply an instance of `PARCObjectDescriptor` containing
+ * configuration information used and pointers to functions that are invoked during the lifecycle of the PARC Object.
+ * Notable functions that are a finalization cleanup function for an object that will be deallocated,
+ * a clone function for an object that is being cloned,
+ * and a string generator for an object that is implementing the `ToString` function.
+ * Implementors of modules that use PARCObject supply a specification of callback
+ * functions that implement specific behaviours for interfaces using PARC Object.
+ *
+ */
+#ifndef libparc_parc_Object_h
+#define libparc_parc_Object_h
+
+#include <stdint.h>
+#include <time.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_CMacro.h>
+//#include <parc/algol/parc_JSON.h>
+//#include <parc/algol/parc_HashCode.h>
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcObject_OptionalAssertValid(_instance_)
+#else
+# define parcObject_OptionalAssertValid(_instance_) parcObject_AssertValid(_instance_)
+#endif
+
+//Switch to strong type after subclasses are converted
+//typedef struct {int unused;} PARCObject;
+typedef void PARCObject;
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct PARCObjectDescriptor PARCObjectDescriptor;
+
+/**
+ * @define parcObject_DescriptorName(_type)
+ *
+ * Compose the token for a subtype specific name for a subtype's `PARCObjectDescriptor`
+ * which is a parameter to `parcObject_Create`.
+ *
+ * For example
+ * @code
+ * parcObject_DescriptorName(MyType)
+ * @endcode
+ *
+ * generates the token `MyType_Descriptor`
+ *
+ * Implementations should use this macro, rather than hardcode the format in their code.
+ */
+#define parcObject_DescriptorName(_type) parcCMacro_Cat(_type, _Descriptor)
+
+/**
+ * @define parcObjectDescriptor_Declaration(_type_)
+ *
+ * Create a declaration of a `PARCObjectDescriptor` implementation.
+ * To define the actual implementation, use `parcObject_Override`
+ */
+#define parcObjectDescriptor_Declaration(_type_) const PARCObjectDescriptor parcObject_DescriptorName(_type_)
+
+/**
+ * @define parcObject_Declare(_type_)
+ *
+ * Create a declaration of a `PARCObject` implementation.
+ * This causes the corresponding `typedef` to be defined
+ * and the global PARCObjectDescriptor corresponding to the declared type.
+ */
+#define parcObject_Declare(_type_) \
+ typedef struct _type_ _type_; \
+ extern parcObjectDescriptor_Declaration(_type_)
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_JSON.h>
+
+/**
+ * A Function that performs the final cleanup and resource deallocation when
+ * a PARC Object has no more references.
+ *
+ * This is deprecated and will be removed.
+ * Use `PARCObjectDestructor`
+ */
+typedef void (PARCObjectDestroy)(PARCObject **);
+
+/**
+ * A Function that performs the final cleanup and resource deallocation when
+ * a PARC Object has no more references.
+ *
+ * If the function returns `true` the object is automatically deallocated and destroyed.
+ * If the function returns `false` the object is not automatically deallocated and destroyed,
+ * and the responsibility for the object's state and memory are the responsibility of
+ * the `PARCObjectDestructor` function.
+ */
+typedef bool (PARCObjectDestructor)(PARCObject **);
+
+/**
+ * A Function that releases one reference to the given PARC Object.
+ * On the final release, where the number of references becomes 0,
+ * the PARCObjectDestroy function is invoked.
+ */
+typedef void (PARCObjectRelease)(PARCObject **objectPointer);
+
+/**
+ * A function that produces a deep-copy of the given PARC Object instance.
+ */
+typedef PARCObject *(PARCObjectCopy)(const PARCObject *object);
+
+/**
+ * A function that invokes the proper _Equals() function for two PARC Object instances.
+ */
+typedef bool (PARCObjectEquals)(const PARCObject *objectX, const PARCObject *objectY);
+
+/**
+ * A function that invokes the proper _Compare() functions for two PARC Object instances.
+ */
+typedef int (PARCObjectCompare)(const PARCObject *, const PARCObject *);
+
+/**
+ * A function that computes the 32-bit hashcode of the given PARC Object instance.
+ */
+typedef PARCHashCode (PARCObjectHashCode)(const PARCObject *object);
+
+/**
+ * A function that produces a C style nul-terminated string representation of the given PARC Object instance.
+ */
+typedef char *(PARCObjectToString)(const PARCObject *object);
+
+/**
+ * A function that displays a human readable representation of the given PARCObject.
+ */
+typedef void (PARCObjectDisplay)(const PARCObject *object, const int indentation);
+
+/**
+ * A function that generates a JSON representation of the given PARC Object instance.
+ */
+typedef PARCJSON *(PARCObjectToJSON)(const PARCObject *);
+
+/**
+ * Every PARCObject descriptor has a pointer to a `PARCObjectState`
+ * containing arbitrary data related to all instances sharing the descriptor.
+ */
+typedef void PARCObjectTypeState;
+
+/**
+ * Every PARC Object instance contains a pointer to an instance of this structure defining
+ * the canonical meta-data for the object.
+ */
+struct PARCObjectDescriptor {
+ char name[64];
+ PARCObjectDestroy *destroy;
+ PARCObjectDestructor *destructor;
+ PARCObjectRelease *release;
+ PARCObjectCopy *copy;
+ PARCObjectToString *toString;
+ PARCObjectEquals *equals;
+ PARCObjectCompare *compare;
+ PARCObjectHashCode *hashCode;
+ PARCObjectToJSON *toJSON;
+ PARCObjectDisplay *display;
+ const struct PARCObjectDescriptor *super;
+ size_t objectSize;
+ unsigned objectAlignment;
+ bool isLockable;
+ PARCObjectTypeState *typeState;
+};
+
+
+/**
+ * Create an allocated instance of `PARCObjectDescriptor`.
+ *
+ * @param [in] name A nul-terminated, C string containing the name of the object descriptor.
+ * @param [in] objectSize The number of bytes necessary to contain the object.
+ * @param [in] objectAlignment The alignment boundary necessary for the object, a power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] isLockable True, if this object implementation supports locking.
+ * @param [in] destructor The callback function to call when the last `parcObject_Release()` is invoked (replaces @p destroy).
+ * @param [in] release The callback function to call when `parcObject_Release()` is invoked.
+ * @param [in] copy The callback function to call when parcObject_Copy() is invoked.
+ * @param [in] toString The callback function to call when `parcObject_ToString()` is invoked.
+ * @param [in] equals The callback function to call when `parcObject_Equals()` is invoked.
+ * @param [in] compare The callback function to call when `parcObject_Compare()` is invoked.
+ * @param [in] hashCode The callback function to call when `parcObject_HashCode()` is invoked.
+ * @param [in] toJSON The callback function to call when `parcObject_ToJSON()` is invoked.
+ * @param [in] display The callback function to call when `parcObject_Display()` is invoked.
+ * @param [in] super A pointer to a `PARCObjectDescriptor` for the supertype of created `PARCObjectDescriptor`
+ * @param [in] typeState A pointer to a `PARCObjectTypeState` for the per-type data for the created `PARCObjectDescriptor`
+ *
+ * @return NULL Memory could not be allocated to store the `PARCObjectDescriptor` instance.
+ * @return non-NULL Successfully created the implementation
+ */
+PARCObjectDescriptor *parcObjectDescriptor_Create(const char *name,
+ size_t objectSize,
+ unsigned int objectAlignment,
+ bool isLockable,
+ PARCObjectDestructor *destructor,
+ PARCObjectRelease *release,
+ PARCObjectCopy *copy,
+ PARCObjectToString *toString,
+ PARCObjectEquals *equals,
+ PARCObjectCompare *compare,
+ PARCObjectHashCode *hashCode,
+ PARCObjectToJSON *toJSON,
+ PARCObjectDisplay *display,
+ const PARCObjectDescriptor *superType,
+ PARCObjectTypeState *typeState);
+
+PARCObjectDescriptor *parcObjectDescriptor_CreateExtension(const PARCObjectDescriptor *superType, const char *name);
+
+PARCObjectTypeState *parcObjectDescriptor_GetTypeState(const PARCObjectDescriptor *descriptor);
+
+const PARCObjectDescriptor *parcObjectDescriptor_GetSuperType(const PARCObjectDescriptor *descriptor);
+
+bool parcObjectDescriptor_Destroy(PARCObjectDescriptor **descriptorPointer);
+
+/**
+ * The globally available `PARCObject` descriptor.
+ */
+extern parcObjectDescriptor_Declaration(PARCObject);
+
+typedef uint64_t PARCReferenceCount;
+
+/**
+ * Assert that an instance of PARC Object is valid.
+ *
+ * If the instance is not valid, terminate via an assertion.
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] object A pointer to a PARC Object instance.
+ */
+void parcObject_AssertValid(const PARCObject *object);
+
+/**
+ * Determine if an instance of PARCObject is valid.
+ *
+ * A valid PARCObject has non-NULL, it has a reference count > 0,
+ * it is non-zero in length, and has a valid alignment.
+ *
+ * @param [in] object A pointer to a PARC Object instance.
+ *
+ * @return true The PARCObject is valid.
+ * @return true The PARCObject is invalid.
+ */
+bool parcObject_IsValid(const PARCObject *object);
+
+/**
+ * Create a new reference counted object that is a deep copy of the specified object,
+ * if possible, or, otherwise, a shallow copy of the object's total allocation memory.
+ *
+ * The reference count for the new object is 1.
+ *
+ * @param [in] object A pointer to the original object.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new reference counted object.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * struct MyType *copy = parcObject_Copy(t);
+ * }
+ * @endcode
+ *
+ * @see parcObject_Release
+ */
+PARCObject *parcObject_Copy(const PARCObject *object);
+
+/**
+ * Compare two object instances.
+ *
+ * The comparison function in the first `PARCObjectDescriptor` parameter is used for comparison.
+ * The objects are expected to be of the same type. Thus, if the comparison function
+ * associated with the first `PARCObjectDescriptor` function is NULL, it is assumed the
+ * same holds for the second parameter. In this case, the instance pointers are compared.
+ *
+ * @param [in] x An object.
+ * @param [in] y An object.
+ *
+ * @return int The result of the comparison.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * int compareResult = parcObject_Compare(t, t);
+ * printf("0? %d\n", compareResult);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+int parcObject_Compare(const PARCObject *x, const PARCObject *y);
+
+/**
+ * Determine if two PARCObject instances are equal.
+ *
+ * Two PARCObject instances are equal if, and only if, the instance pointers are equal.
+ *
+ * The following equivalence relations on non-null `PARCObject` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCObject_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcObject_Equals(x, y)` must return true if and only if
+ * `parcObject_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcObject_Equals(x, y)` returns true and
+ * `parcObject_Equals(y, z)` returns true,
+ * then `parcObject_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcObject_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcObject_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param x A pointer to a `PARCObject` instance.
+ * @param y A pointer to a `PARCObject` instance.
+ * @return true if the two `PARCObject` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *a = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ * struct MyType *b = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * if (parcObject_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_Equals(const PARCObject *x, const PARCObject *y);
+
+/**
+ * Retrieve the hashcode of the given object.
+ *
+ * If no object implementation is provided, the hashcode is the 32-bit address
+ * of the base object pointer. Otherwise, the hashcode is computed by the
+ * provided hashcode function.
+ *
+ * @param [in] object An object.
+ *
+ * @return uint32_t The object hashcode
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCHashCode hashcode = parcObject_HashCode(t);
+ * printf("Hashcode = %" PRIXPARCHashCode "\n", hashcode);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+PARCHashCode parcObject_HashCode(const PARCObject *object);
+
+/**
+ * Create a C string containing a human readable representation of the given object.
+ *
+ * @param [in] object The object from which a string representation will be generated.
+ *
+ * @return NULL Memory could not be allocated to contain the C string.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * char *string = parcObject_ToString(t);
+ * printf("%s\n", string);
+ * parcMemory_Deallocate((void **) &string);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+char *parcObject_ToString(const PARCObject *object);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] object The object from which a JSON instance will be generated.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCJSON *json = parcObject_ToJSON(t);
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+PARCJSON *parcObject_ToJSON(const PARCObject *object);
+
+/**
+ * Acquire a new reference to an object.
+ *
+ * The reference count to the object is incremented.
+ *
+ * @param [in] object The object to which to refer.
+ *
+ * @return The same value as the input parameter @p object
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * struct MyType *new = parcObject_Acquire(t);
+ *
+ * parcObject_Release(&t);
+ * parcObject_Release(&new);
+ * }
+ * @endcode
+ */
+PARCObject *parcObject_Acquire(const PARCObject *object);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If an invocation of `parcObject_Release` causes the last reference to
+ * the instance to be released, it calls the instance's `destructor` function
+ * specified in the `PARCObjectDescriptor` structure supplied when the instance
+ * was created (see `parcObject_Create`.
+ *
+ * The contents of the deallocated memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in] objectPointer A pointer to a pointer to the instance to release.
+ *
+ * @return The number of remaining references to the object.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ *
+ * @see parcObject_Create
+ * @see parcObject_Acquire
+ */
+PARCReferenceCount parcObject_Release(PARCObject **objectPointer);
+
+/**
+ * Get the current `PARCReferenceCount` for the specified object.
+ *
+ * The reference count must always be greater than zero.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return The current reference count for the specified object.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCReferenceCount count = parcObject_GetReferenceCount(t);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ *
+ * @see parcObject_Acquire
+ * @see parcObject_Release
+ */
+PARCReferenceCount parcObject_GetReferenceCount(const PARCObject *object);
+
+/**
+ * Print a human readable representation of the given `PARC Object.
+ *
+ * @param [in] object A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * parcObject_Display(t, 0);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+void parcObject_Display(const PARCObject *object, const int indentation);
+
+/**
+ * Get the `PARCObjectDescriptor` of the given `PARCObject`.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance
+ *
+ * @return A pointer to the given PARCObject's `PARCObjectDescriptor`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCObjectDescriptor *descriptor = parcObject_GetDescriptor(t);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+const PARCObjectDescriptor *parcObject_GetDescriptor(const PARCObject *object);
+
+/**
+ * Set the `PARCObjectDescriptor` of the given `PARCObject`.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance
+ * @param [in] objectType A pointer to a valid `PARCObjectDescriptor` instance
+ *
+ * @return The previous value of the given PARCObject's `PARCObjectDescriptor`.
+ */
+const PARCObjectDescriptor *parcObject_SetDescriptor(PARCObject *object, const PARCObjectDescriptor *objectType);
+
+/**
+ * @def parcObject_MetaInitialize
+ * @deprecated Use parcObject_Override instead;
+ *
+ * Initialize a PARCObjectDescriptor structure. Every function pointer is set to NULL.
+ *
+ * @param [in] objectType A pointer to the PARCObjectDescriptor structure to initialize.
+ *
+ * @return The pointer to the initialized PARCObjectDescriptor.
+ */
+#define parcObject_MetaInitialize(objectType) \
+ (objectType)->destructor = NULL, \
+ (objectType)->destroy = NULL, \
+ (objectType)->release = NULL, \
+ (objectType)->copy = NULL, \
+ (objectType)->toString = NULL, \
+ (objectType)->equals = NULL, \
+ (objectType)->compare = NULL, \
+ (objectType)->hashCode = NULL, \
+ (objectType)->toJSON = NULL, \
+ (objectType)->display = NULL, \
+ (objectType)->super = NULL
+
+
+/**
+ * Create new `PARCObjectDescriptor` based on an existing `PARCObjectDescriptor.`
+ * The new `PARCObjectDescriptor` uses the existing `PARCObjectDescriptor` as the super-type of the new descriptor.
+ */
+#define parcObject_Extends(_subtype, _superType, ...) \
+ LongBowCompiler_IgnoreInitializerOverrides \
+ parcObjectDescriptor_Declaration(_subtype) = { \
+ .super = &parcObject_DescriptorName(_superType), \
+ .name = #_subtype, \
+ .objectSize = 0, \
+ .objectAlignment = 0, \
+ .destroy = NULL, \
+ .destructor = NULL, \
+ .release = NULL, \
+ .copy = NULL, \
+ .toString = NULL, \
+ .equals = NULL, \
+ .compare = NULL, \
+ .hashCode = NULL, \
+ .toJSON = NULL, \
+ .display = NULL, \
+ .isLockable = true, \
+ .typeState = NULL, \
+ __VA_ARGS__ \
+ }; \
+ LongBowCompiler_WarnInitializerOverrides \
+ const PARCObjectDescriptor parcObject_DescriptorName(_subtype)
+
+/**
+ * Define a new PARC Object implementation, by composing a new PARC Object Descriptor referencing an old one.
+ * The new PARC Object implementation must be accompanied by the corresponding `typedef` of the type containing the object's data.
+ */
+#define parcObject_Override(_subtype, _superType, ...) \
+ parcObject_Extends(_subtype, _superType, \
+ .objectSize = sizeof(_subtype), \
+ .objectAlignment = sizeof(void *), \
+ __VA_ARGS__)
+
+
+/// Helper MACROS for PARCObject Normalization
+/** \cond */
+/**
+ * parcObject_DestroyWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * destroy operation. Intended for internal use.
+ */
+#define parcObject_DestroyWrapper(_type, _fname) \
+ static void _autowrap_destroy_ ## _type(PARCObject **object) \
+ { \
+ _fname((_type **) object); \
+ }
+
+/**
+ * parcObject_DestructorWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * destroy operation. Intended for internal use.
+ */
+#define parcObject_DestructorWrapper(_type, _fname) \
+ static bool _autowrap_destructor_ ## _type(PARCObject **object) \
+ { \
+ return _fname((_type **) object); \
+ }
+
+/**
+ * `parcObject_CopyWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * copy operation. Intended for internal use.
+ */
+#define parcObject_CopyWrapper(_type, _fname) \
+ static PARCObject *_autowrap_copy_ ## _type(const PARCObject *object) \
+ { \
+ return (PARCObject *) _fname((const _type *) object); \
+ }
+
+/**
+ * parcObject_ToStringWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * ToString operation. Intended for internal use.
+ */
+#define parcObject_ToStringWrapper(_type, _fname) \
+ static char *_autowrap_toString_ ## _type(const PARCObject *object) \
+ { \
+ return _fname((const _type *) object); \
+ }
+
+/**
+ * `parcObject_EqualsWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * equals operation. Intended for internal use.
+ */
+#define parcObject_EqualsWrapper(_type, _fname) \
+ static bool _autowrap_equals_ ## _type(const PARCObject *a, const PARCObject *b) \
+ { \
+ return _fname((const _type *) a, (const _type *) b); \
+ }
+
+/**
+ * parcObject_CompareWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * compare operation. Intended for internal use.
+ */
+#define parcObject_CompareWrapper(_type, _fname) \
+ static int _autowrap_compare_ ## _type(const PARCObject *a, const PARCObject *b) \
+ { \
+ return _fname((const _type *) a, (const _type *) b); \
+ }
+
+/**
+ * `parcObject_HashCodeWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * HashCode operation. Intended for internal use.
+ */
+#define parcObject_HashCodeWrapper(_type, _fname) \
+ static PARCHashCode _autowrap_hashCode_ ## _type(const PARCObject *object) \
+ { \
+ return _fname((const _type *) object); \
+ }
+
+/**
+ * `parcObject_CopyWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * ToJSON operation. Intended for internal use.
+ */
+#define parcObject_ToJSONWrapper(_type, _fname) \
+ static PARCJSON *_autowrap_toJSON_ ## _type(const PARCObject *object) \
+ { \
+ return _fname((const _type *) object); \
+ }
+
+/**
+ * `parcObject_DisplayWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * Display operation. Intended for internal use.
+ */
+#define parcObject_DisplayWrapper(_type, _fname) \
+ static void _autowrap_Display_ ## _type(const PARCObject *object, const int indentation) \
+ { \
+ _fname((const _type *) object, indentation); \
+ }
+
+/**
+ * _autowrap_NULL is a part of the c-macro trick for implement a macro If-Else switch.
+ * If included as a macro parameter it inserts a comma into the parameter list for that macro.
+ * This can be used by a switching macro that always resolves to the nth element and the
+ * presence of a comma generating macro changes which element is the nth. When NULL is used
+ * as a parameter in a call to "ExtendPARCObject", _autowrap_NULL will be the name generated which
+ * expands to a comma.
+ */
+#define _autowrap_NULL(...) ,
+
+/** \endcond */
+
+
+/**
+ * @define parcObject_ExtendPARCObject
+ * @deprecated Use parcObject_Override instead;
+ *
+ * @discussion parcObject_ExtendPARCObject is a helper macro for constructing a PARCObjectDescriptor Structure of
+ * function pointers pointing to a subtype's overriding functions. This struct serves the same
+ * purpose as a vTable in c++ and provides for simple polymorphism. The functions used as parameters
+ * should NOT call through to the parcObject function they override as this will result in an infinite loop.
+ * NULL should be used for functions where PARCObject's default implementation is desired.
+ *
+ * Note: It uses the parcCMacro_IfElse trickery to handle NULL parameters.
+ *
+ * @param [in] _destroy A pointer to the Destroy callback function.
+ * @param [in] _copy A pointer to the Copy callback function.
+ * @param [in] _toString A pointer to the ToString callback function.
+ * @param [in] _equals A pointer to the Equals callback function.
+ * @param [in] _compare A pointer to the Compare callback function.
+ * @param [in] _hashCode A pointer to the HashCode callback function.
+ * @param [in] _toJSON A pointer to the ToJSON callback function.
+ */
+#define parcObject_ExtendPARCObject(_type, _destroy, _copy, _toString, _equals, _compare, _hashCode, _toJSON) \
+ parcCMacro_IfElse(, parcObject_DestroyWrapper(_type, _destroy), _autowrap_ ## _destroy()) \
+ parcCMacro_IfElse(, parcObject_CopyWrapper(_type, _copy), _autowrap_ ## _copy()) \
+ parcCMacro_IfElse(, parcObject_ToStringWrapper(_type, _toString), _autowrap_ ## _toString()) \
+ parcCMacro_IfElse(, parcObject_EqualsWrapper(_type, _equals), _autowrap_ ## _equals()) \
+ parcCMacro_IfElse(, parcObject_CompareWrapper(_type, _compare), _autowrap_ ## _compare()) \
+ parcCMacro_IfElse(, parcObject_HashCodeWrapper(_type, _hashCode), _autowrap_ ## _hashCode()) \
+ parcCMacro_IfElse(, parcObject_ToJSONWrapper(_type, _toJSON), _autowrap_ ## _toJSON()) \
+ parcObject_Override(_type, PARCObject, \
+ .destroy = parcCMacro_IfElse(NULL, _autowrap_destroy_ ## _type, _autowrap_ ## _destroy()), \
+ .destructor = NULL, \
+ .release = NULL, \
+ .copy = parcCMacro_IfElse(NULL, _autowrap_copy_ ## _type, _autowrap_ ## _copy()), \
+ .toString = parcCMacro_IfElse(NULL, _autowrap_toString_ ## _type, _autowrap_ ## _toString()), \
+ .equals = parcCMacro_IfElse(NULL, _autowrap_equals_ ## _type, _autowrap_ ## _equals()), \
+ .compare = parcCMacro_IfElse(NULL, _autowrap_compare_ ## _type, _autowrap_ ## _compare()), \
+ .hashCode = parcCMacro_IfElse(NULL, _autowrap_hashCode_ ## _type, _autowrap_ ## _hashCode()), \
+ .toJSON = parcCMacro_IfElse(NULL, _autowrap_toJSON_ ## _type, _autowrap_ ## _toJSON()), \
+ .display = NULL)
+
+/**
+ * @define parcObject_CreateInstance
+ *
+ * `parcObject_CreateInstance` is a helper C-macro that creates an instance of a PARCObject subtype
+ * using `parcObject_CreateInstanceImpl` that is based on the PARCObjectDescriptor.
+ *
+ * @param [in] _subtype A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_CreateInstance(_subtype) \
+ parcObject_CreateInstanceImpl(&parcObject_DescriptorName(_subtype))
+
+PARCObject *parcObject_CreateInstanceImpl(const PARCObjectDescriptor *descriptor);
+
+/**
+ * @define parcObject_CreateAndClearInstance
+ *
+ * parcObject_CreateAndClearInstance is a helper C-macro that creates an instance of a PARCObject subtype
+ * using parcObject_CreateAndClear that is based on the PARCObjectDescriptor struct created by the
+ * parcObject_ExtendPARCObject macro.
+ *
+ * @param [in] _subtype A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_CreateAndClearInstance(_subtype) \
+ (_subtype *) parcObject_CreateAndClearInstanceImpl(&parcObject_DescriptorName(_subtype))
+
+/**
+ * Create a reference counted segment of memory of at least @p objectLength long.
+ *
+ * The implementation pointer, is either NULL or points to a valid `PARCObjectDescriptor` structure
+ * containing the callback functions that implement the object's life-cycle operations.
+ *
+ * The allocated memory is such that the memory's base address is aligned on a sizeof(void *) boundary,
+ * and filled with zero bytes.
+ *
+ * If memory cannot be allocated, `errno` is set to ENOMEM.
+ *
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` structure.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A pointer to reference counted memory of at least length bytes.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval *t = parcObject_CreateAndClearInstanceImpl(sizeof(struct timeval), &PARCObject_Descriptor);
+ * }
+ * @endcode
+ *
+ * @see PARCObjectDescriptor
+ * @see parcObject_Create
+ */
+PARCObject *parcObject_CreateAndClearInstanceImpl(const PARCObjectDescriptor *descriptor);
+
+/**
+ * Define a static PARCObject instance for the given type, alignment, per-object data.
+ *
+ * Once the instance has been defined, it must be initialised via `parcObject_InitInstance`
+ * or `parcObject_InitAndClearInstance` before it is used.
+ *
+ * @return A pointer to an invalid `PARCObject` instance that must be initialised .
+ */
+#define parcObject_Instance(_type_, _alignment_, _size_) \
+ (_type_ *) (& (char[parcObject_TotalSize(_alignment_, _size_)]) { 0 }[parcObject_PrefixLength(sizeof(void *))])
+
+/**
+ * @define parcObject_InitInstance
+ *
+ * `parcObject_InitInstance` is a helper C-macro that initializes a portion of memory to contain a `PARCObject` subtype
+ * using `parcObject_InitInstanceImpl`.
+ *
+ * @param [in] _object_ A pointer to memory that will contain the object and its meta-data.
+ * @param [in] _subtype A subtype's type name.
+ */
+#define parcObject_InitInstance(_object_, _subtype) \
+ parcObject_InitInstanceImpl(_object_, &parcObject_DescriptorName(_subtype))
+
+/**
+ * @define parcObject_InitInstanceImpl
+ *
+ * Initialize a PARCObject instance given the `PARCObjectDescriptor`.
+ * Any previous state of the given PARCObject is destroyed.
+ *
+ * @param [in] object A pointer to an existing valid or invalid `PARCObject` instance.
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` structure.
+ */
+PARCObject *parcObject_InitInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor);
+
+/**
+ * @define parcObject_InitAndClearInstance
+ *
+ * `parcObject_InitAndClearInstance` is a helper C-macro that initializes a portion of memory to contain a PARCObject subtype
+ * using `parcObject_InitAndClearInstanceImpl`.
+ *
+ * @param [in] _object_ A pointer to memory that will contain the object and its meta-data.
+ * @param [in] _subtype A subtype's type name.
+ */
+#define parcObject_InitAndClearInstance(_object_, _subtype) \
+ parcObject_InitAndClearInstanceImpl(_object_, &parcObject_DescriptorName(_subtype))
+
+/**
+ * Create a reference counted segment of memory of at least @p objectLength long.
+ *
+ * The implementation pointer, is either NULL or points to a valid `PARCObjectDescriptor` structure
+ * containing the callback functions that implement the object's life-cycle operations.
+ *
+ * The allocated memory is such that the memory's base address is aligned on a sizeof(void *) boundary,
+ * and filled with zero bytes.
+ *
+ * If memory cannot be allocated, `errno` is set to `ENOMEM`.
+ *
+ * @param [in] object A pointer to an existing valid or invalid `PARCObject` instance.
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` structure.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A pointer to reference counted memory of at least length bytes.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * }
+ * @endcode
+ *
+ * @see PARCObjectDescriptor
+ * @see parcObject_Create
+ */
+PARCObject *parcObject_InitAndClearInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor);
+
+/**
+ * Compute the number of bytes necessary for a PARC Object prefix.
+ *
+ * The @p _alignment_ parameter specifies the required memory alignment of the object.
+ *
+ * @param [in] _alignment_ An unsigned integer value greater than `sizeof(void *)`
+ *
+ * @return The number of bytes necessary for a PARC Object header.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+// The constant value here must be greater than or equal to the size of the internal _PARCObjectHeader structure.
+#define parcObject_PrefixLength(_alignment_) ((152 + (_alignment_ - 1)) & - _alignment_)
+
+/**
+ * Compute the number of bytes necessary for a PARC Object.
+ *
+ * The number of bytes consists of the number of bytes for the PARC Object header, padding, and the object's specific data.
+ *
+ * The @p _alignment_ parameter specifies the required memory alignment of the object.
+ * The @p _size_ parameter specifies the number of bytes necessary for the object specific data.
+ */
+#define parcObject_TotalSize(_alignment_, _size_) (parcObject_PrefixLength(_alignment_) + _size_)
+
+/**
+ * Wrap a static, unallocated region of memory producing a valid pointer to a `PARCObject` instance.
+ *
+ * Note that the return value will not be equal to the value of @p origin.
+ *
+ * @param [in] memory A pointer to memory that will contain the object and its state.
+ * @param [in] descriptor The subtype name that will be used to compose the name of the `PARCObjectDescriptor` for the object.
+ *
+ * @return NULL An error occured.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+#define parcObject_Wrap(_memory_, _subtype) \
+ parcObject_WrapImpl(_memory_, &parcObject_DescriptorName(_subtype))
+
+/**
+ * Wrap a static, unallocated region of memory producing a valid pointer to a `PARCObject` instance.
+ *
+ * Note that the return value will not be equal to the value of @p origin.
+ *
+ * @param [in] memory A pointer to memory that will contain the object and its state.
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` for the object.
+ *
+ * @return NULL An error occured.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCObject *parcObject_WrapImpl(void *memory, const PARCObjectDescriptor *descriptor);
+
+/**
+ * @def parcObject_ImplementAcquire
+ *
+ * `parcObject_ImplementAcquire` is a helper C-macro that creates a canonical subtype specific
+ * Acquire function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. parcBuffer)
+ * @param [in] _type A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_ImplementAcquire(_namespace, _type) \
+ _type * _namespace ## _Acquire(const _type * pObject) { \
+ return (_type *) parcObject_Acquire((PARCObject *) pObject); \
+ } extern _type *_namespace ## _Acquire(const _type * pObject)
+
+/**
+ * @def parcObject_ImplementRelease
+ *
+ * `parcObject_ImplementRelease` is a helper C-macro that creates a canonical subtype specific
+ * Release function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. parcBuffer)
+ * @param [in] _type A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_ImplementRelease(_namespace, _type) \
+ inline void _namespace ## _Release(_type **pObject) { \
+ parcObject_Release((PARCObject **) pObject); \
+ } extern void _namespace ## _Release(_type **pObject)
+
+/**
+ * `parcObject_ImplementationCheck` is a helper macro that will generate compile time warnings for
+ * missing canonical functions or canonical functions with faulty signatures.
+ *
+ * @param _namespace A subtype's namespace string (e.g. parcBuffer)
+ * @param _type A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_ImplementationCheck(_namespace, _type) \
+ static void \
+ _impl_check() { \
+ _type *po; \
+ const _type co; \
+ const _type *pco; \
+ pco = _namespace ## _Copy(&co); \
+ pco = _namespace ## _Acquire(&co); \
+ pco = pco; \
+ _namespace ## _Release(&po); \
+ bool b = _namespace ## _Equals(&co, &co); \
+ b = b; \
+ int i = _namespace ## _Compare(&co, &co); \
+ i = i; \
+ char *pc = _namespace ## _ToString(&co); \
+ pc = pc; \
+ uint32_t ui = _namespace ## _HashCode(&co); \
+ ui = ui; \
+ PARCJSON *pj = _namespace ## _ToJSON(&co); \
+ pj = pj; \
+ } typedef void parcCMacro_Cat (_type, _IC_NOOP)
+
+/**
+ * Obtain the lock on the given `PARCObject` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, the `PARCObject` is invalid, or does not support locking.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_Lock(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementLock
+ *
+ * `parcObject_ImplementLock` is a helper C-macro that defines a static, inline facade for the `parcObject_Lock` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementLock(_namespace, _type) \
+ static inline bool _namespace ## _Lock(const _type * pObject) { \
+ return parcObject_Lock((PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Lock_NOOP)
+
+/**
+ * Try to obtain the advisory lock on the given `PARCObject` instance.
+ *
+ * Once the lock is obtained, the caller must release the lock via `parcObject_Unlock`.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The `PARCObject` is locked.
+ * @return false The `PARCObject` is unlocked, or does not support locking.
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcObject_TryLock(object))
+ * ;
+ * }
+ * @endcode
+ */
+bool parcObject_TryLock(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementTryLock
+ *
+ * `parcObject_ImplementTryLock` is a helper C-macro that defines a static, inline facade for the `parcObject_TryLock` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementTryLock(_namespace, _type) \
+ static inline bool _namespace ## _TryLock(const _type * pObject) { \
+ return parcObject_TryLock((PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _TryLock_NOOP)
+
+/**
+ * Try to unlock the advisory lock on the given `PARCObject` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The `PARCObject` was locked and now is unlocked.
+ * @return false The `PARCObject` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(Object)) {
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_Unlock(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementUnlock
+ *
+ * `parcObject_ImplementUnlock` is a helper C-macro that defines a static, inline facade for the `parcObject_Unlock` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementUnlock(_namespace, _type) \
+ static inline bool _namespace ## _Unlock(const _type * pObject) { \
+ return parcObject_Unlock((PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Unlock_NOOP)
+
+/**
+ * Determine if the advisory lock on the given PARCObject instance is locked.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ *
+ * @return true The `PARCObject` is locked.
+ * @return false The `PARCObject` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * ...
+ * if (parcObject_IsLocked(object) {
+ * ....
+ * }
+ * ...
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_IsLocked(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementIsLocked
+ *
+ * parcObject_ImplementIsLocked is a helper C-macro that defines a static, inline facade for the `parcObject_IsLocked` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementIsLocked(_namespace, _type) \
+ static inline bool _namespace ## _IsLocked(const _type * pObject) { \
+ return parcObject_IsLocked((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _IsLocked_NOOP)
+
+/**
+ * Causes the calling thread to wait until another thread invokes the `parcObject_Notify()` function on the same object.
+ *
+ * The calling thread must own this object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes `parcObject_Notify`
+ * on the same object. The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * ...
+ * if (parcObject_Wait(object) {
+ * ....
+ * }
+ * ...
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+void parcObject_Wait(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementWait
+ *
+ * parcObject_ImplementWait is a helper C-macro that defines a static, inline facade for the `parcObject_Wait` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ * @see parcObject_Wait
+ */
+#define parcObject_ImplementWait(_namespace, _type) \
+ static inline void _namespace ## _Wait(const _type * pObject) { \
+ parcObject_Wait((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Wait_NOOP)
+
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the `parcObject_Notify()`
+ * function on the same object or the system time equals or exceeds the specified time.
+ *
+ * The calling thread must own the object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes
+ * `parcObject_Notify` or the computer's system time equals or exceeds that specified by @p time.
+ * on the same object.
+ * The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ *
+ * @returns false if the alloted time was exceeded.
+ * @returns true if another thread invoked the `parcObject_Notify()` function
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval tv;
+ * gettimeofday(&tv, NULL);
+ *
+ * struct timespec absoluteTime;
+ * absoluteTime.tv_sec = tv.tv_sec + 0;
+ * absoluteTime.tv_nsec = 0;
+ *
+ * parcObject_WaitUntil(object, &absoluteTime);
+ * }
+ * @endcode
+ */
+bool parcObject_WaitUntil(const PARCObject *object, const struct timespec *time);
+
+/**
+ * @def parcObject_ImplementWaitUntil
+ *
+ * parcObject_ImplementWaitUntil is a helper C-macro that defines a static, inline facade for the
+ * `parcObject_WaitUntil` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ * @see parcObject_WaitUntil
+ */
+#define parcObject_ImplementWaitUntil(_namespace, _type) \
+ static inline bool _namespace ## _WaitUntil(const _type * pObject, const struct timespec *time) { \
+ return parcObject_WaitUntil((const PARCObject *) pObject, time); \
+ } typedef void parcCMacro_Cat (_type, _WaitUntil_NOOP)
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the `parcObject_Notify()`
+ * function on the same object or the given number of nanoseconds elapses.
+ *
+ * The calling thread must own the object's lock.
+ *
+ * The calling thread will release ownership of its lock and wait until another thread invokes
+ * `parcObject_Notify` on the same object,
+ * or the computer's system time equals or exceeds the time specified by the
+ * time of invocation plus nanoSeconds.
+ * The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ * @param [in] nanoSeconds The number of nanoseconds to wait.
+ *
+ * @returns false if the allotted time was exceeded.
+ * @returns true if another thread invoked the `parcObject_Notify()` function
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_WaitFor(object, 1000000000UL);
+ * }
+ * @endcode
+ */
+bool parcObject_WaitFor(const PARCObject *object, const uint64_t nanoSeconds);
+
+/**
+ * @def parcObject_ImplementWaitUntil
+ *
+ * parcObject_ImplementWaitUntil is a helper C-macro that defines a static, inline facade for the
+ * `parcObject_WaitUntil` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ * @see parcObject_WaitUntil
+ */
+#define parcObject_ImplementWaitFor(_namespace, _type) \
+ static inline bool _namespace ## _WaitFor(const _type * pObject, const unsigned long nanoSeconds) { \
+ return parcObject_WaitFor((const PARCObject *) pObject, nanoSeconds); \
+ } typedef void parcCMacro_Cat (_type, _WaitFor_NOOP)
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcObject_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example,
+ * the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * parcObject_Notify(object);
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+void parcObject_Notify(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementNotify
+ *
+ * parcObject_ImplementNotify is a helper C-macro that defines a static, inline facade for the `parcObject_Notify` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementNotify(_namespace, _type) \
+ static inline void _namespace ## _Notify(const _type * pObject) { \
+ parcObject_Notify((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Notify_NOOP)
+
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcObject_Wait`, `parcObject_WaitFor`, `parcObject_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * parcObject_NotifyAll(object);
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+void parcObject_NotifyAll(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementNotifyAll
+ *
+ * parcObject_ImplementNotifyAll is a helper C-macro that defines a static, inline facade for the `parcObject_NotifyAll` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementNotifyAll(_namespace, _type) \
+ static inline void _namespace ## _NotifyAll(const _type * pObject) { \
+ parcObject_NotifyAll((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _NotifyAll_NOOP)
+
+/**
+ * @def parcObject_Mutex
+ *
+ * This macro uses the functions `parcObject_Lock` and `parcObject_Unlock`
+ * to provide a simple syntax for implementing a mutual exclusion region of code.
+ *
+ * @param [in] _object_ A pointer to a valid PARCObject that implements locking.
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_Mutex(object) {
+ * ....
+ * }
+ * }
+ * @endcode
+ * @see parcObject_Synchronize
+ */
+#define parcObject_Mutex(_object_) for (bool once = true; once && parcObject_Lock(_object_); parcObject_Unlock(_object_), once = false)
+
+/**
+ * Determine if a given `PARCObject` is and instance of the specified `PARCObjectDescriptor`.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ * @param [in] descriptor A pointer to a valid PARCObjectDescriptor instance.
+ *
+ * @return true @p object is an instance of @p descriptor.
+ * @return false @p object is not an instance of @p descriptor.
+ */
+bool parcObject_IsInstanceOf(const PARCObject *object, const PARCObjectDescriptor *descriptor);
+
+/**
+ * Atomically set an object's barrier.
+ *
+ * If the barrier is not set, the barrier will be set and this function returns `true`.
+ *
+ * If the barrier is already set, any subsequent attempt to set the barrier will block until the barrier is unset
+ * (see `parcObject_BarrierUnset`).
+ * If there are multiple competitors to set the barrier,
+ * only one will (indiscriminately) succeed and return and the remaining will continue to attempt to set the barrier.
+ *
+ * Barriers can be used in both threaded and non-threaded applications,
+ * but are not a substitute for thread locking and do not interoperate the wait and notify operations.
+ *
+ * Barriers should be used in pairs within the same level of program abstraction to avoid confusion.
+ * It is possible to set a barrier without ever unsetting the same barrier,
+ * and as a consequence any other attempt to set the same barrier will hang the program.
+ *
+ * @param [in] object A pointer to a valid PARCObject
+ *
+ * @return true
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_BarrierSet(object);
+ *
+ * ...
+ *
+ * parcObject_BarrierUnset(object);
+ * }
+ * @endcode
+ * @see parcObject_BarrierUnset
+ * @see parcObject_Synchronize
+ */
+bool parcObject_BarrierSet(const PARCObject *object);
+
+/**
+ * Unset an objects' barrier.
+ *
+ * If a barrier is set (see `parcObject_BarrierSet`), the barrier is unset (see `parcObject_BarrierUnset`).
+ *
+ * If a barrier is not set, this function will block until the barrier is set,
+ * whereupon it will be immediately unset the barrier and return.
+ *
+ * If there are multiple competitors attempting to unset the barrier,
+ * only one will (indiscriminately) succeed and return and the remaining will continue to attempt to unset the barrier.
+ *
+ * Barriers are not a substitute for thread locking and do not interoperate the wait and notify operations.
+ *
+ *
+ * @param [in] object A pointer to a valid `PARCObject`
+ *
+ * @return false
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_BarrierSet(object);
+ *
+ * ...
+ *
+ * parcObject_BarrierUnset(object);
+ * }
+ * @endcode
+ */
+bool parcObject_BarrierUnset(const PARCObject *object);
+
+/**
+ * Synchronize on a `PARCObject` instance to provide a simple mutual exclusion region of code.
+ *
+ * This macro uses the functions `parcObject_BarrierSet` and `parcObject_BarrierUnset`
+ * to provide a simple syntax for implementing a mutual exclusion region of code.
+ *
+ * This defines and uses the local variable `_parcObjectSynchronize` which will always appear to be true to the calling function
+ * and must never be defined by the calling function, or any module.
+ *
+ * @param [in] object A pointer to a valid `PARCObject`
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_Synchronize(_object_) {
+ * // Only one thread executes this code at a single time.
+ * }
+ * }
+ * @endcode
+ * @see parcObject_Mutex
+ */
+#define parcObject_Synchronize(_object_) for (bool _parcObjectSynchronize = parcObject_BarrierSet(_object_); _parcObjectSynchronize; _parcObjectSynchronize = parcObject_BarrierUnset(_object_))
+
+#endif // libparc_parc_Object_h
diff --git a/libparc/parc/algol/parc_OldSortedList.c b/libparc/parc/algol/parc_OldSortedList.c
new file mode 100755
index 00000000..ef007388
--- /dev/null
+++ b/libparc/parc/algol/parc_OldSortedList.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_SortedList.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_sorted_list {
+ parcSortedList_Compare compare;
+ PARCArrayList *arrayList;
+};
+
+PARCSortedList *
+parcSortedList_Create(parcSortedList_Compare compareFunction)
+{
+ PARCSortedList *sortedList = parcMemory_Allocate(sizeof(PARCSortedList));
+ assertNotNull(sortedList, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCSortedList));
+ sortedList->arrayList = parcArrayList_Create(NULL);
+ sortedList->compare = compareFunction;
+ return sortedList;
+}
+
+void
+parcSortedList_Destroy(PARCSortedList **parcSortedListPointer)
+{
+ parcArrayList_Destroy(&((*parcSortedListPointer)->arrayList));
+ parcMemory_Deallocate((void **) parcSortedListPointer);
+ *parcSortedListPointer = NULL;
+}
+
+void
+parcSortedList_Add(PARCSortedList *parcSortedList, void *newItem)
+{
+ assertNotNull(parcSortedList, "sortedList parameter can't be null");
+ assertNotNull(parcSortedList->arrayList, "arrayList can't be null");
+ assertNotNull(newItem, "newItem can't be null");
+
+ size_t total_items = parcArrayList_Size(parcSortedList->arrayList);
+ for (size_t i = 0; i < total_items; i++) {
+ void *oldItem = parcArrayList_Get(parcSortedList->arrayList, i);
+ if (parcSortedList->compare(newItem, oldItem) == -1) {
+ // The old item at position i is bigger than the new item,
+ // we must insert the newItem here.
+ parcArrayList_InsertAtIndex(parcSortedList->arrayList, newItem, i);
+ return;
+ }
+ }
+ // We reached the end of the list, it must go here...
+ parcArrayList_Add(parcSortedList->arrayList, newItem);
+}
+
+size_t
+parcSortedList_Length(PARCSortedList *parcSortedList)
+{
+ return parcArrayList_Size(parcSortedList->arrayList);
+}
+
+void *
+parcSortedList_PopFirst(PARCSortedList *parcSortedList)
+{
+ assertNotNull(parcSortedList, "sortedList parameter can't be null");
+ assertNotNull(parcSortedList->arrayList, "arrayList can't be null");
+
+ if (parcArrayList_Size(parcSortedList->arrayList) == 0) {
+ return NULL;
+ }
+ void *item = parcArrayList_Get(parcSortedList->arrayList, 0);
+ parcArrayList_RemoveAndDestroyAtIndex(parcSortedList->arrayList, 0);
+ return item;
+}
+
+void *
+parcSortedList_GetFirst(PARCSortedList *parcSortedList)
+{
+ assertNotNull(parcSortedList, "sortedList parameter can't be null");
+ assertNotNull(parcSortedList->arrayList, "arrayList can't be null");
+
+ if (parcArrayList_Size(parcSortedList->arrayList) == 0) {
+ return NULL;
+ }
+ return parcArrayList_Get(parcSortedList->arrayList, 0);
+}
diff --git a/libparc/parc/algol/parc_OldSortedList.h b/libparc/parc/algol/parc_OldSortedList.h
new file mode 100755
index 00000000..2a00a0fa
--- /dev/null
+++ b/libparc/parc/algol/parc_OldSortedList.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_SortedList.h
+ * @ingroup datastructures
+ * @brief A sorted list
+ *
+ */
+#ifndef libparc_parc_SortedList_h
+#define libparc_parc_SortedList_h
+
+#include <stdlib.h>
+
+struct parc_sorted_list;
+
+typedef struct parc_sorted_list PARCSortedList;
+
+/**
+ * This is a compare function that must be defined for the sorted list to sort
+ *
+ * @param [in] object1 The first object to compare.
+ * @param [in] object2 The second object to compare.
+ * @return -1 if object1 < object2, 0 if object1 == object2, 1 if object1 > object2.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef int (*parcSortedList_Compare)(const void *object1, const void *object2);
+
+/**
+ * Create a sorted list
+ * This list will be sorted from smallest to largest based on the compare function.
+ *
+ * @param [in] compareFunction A compare function to determine how elements are sorted.
+ * @return An allocated `PARCSortedList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Create(parcSortedList_Compare compareFunction);
+
+/**
+ * Destroy an allocated sorted list
+ *
+ * @param [in,out] parcSortedListPointer A pointer to the allocated sorted list to destroy. The pointer will be set to NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcSortedList_Destroy(PARCSortedList **parcSortedListPointer);
+
+/**
+ * Add an element to the sorted list.
+ *
+ * @param [in,out] parcSortedList A pointer to the `PARCSortedList` to modify.
+ * @param newItem The new item to add to the list. This item must be comparable by the compare function.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcSortedList_Add(PARCSortedList *parcSortedList, void *newItem);
+
+/**
+ * Return the length of the list
+ *
+ * @param [in] parcSortedList a pointer to an allocated sorted list.
+ * @return return the length of the list, the number of elements.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcSortedList_Length(PARCSortedList *parcSortedList);
+
+/**
+ * Pop the first element on the sorted list. This will remove the element from the list and return it to the caller.
+ *
+ * @param [in,out] parcSortedList A pointer to the `PARCSortedList` to modify.
+ * @return The first element of @p parcSortedList.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcSortedList_PopFirst(PARCSortedList *parcSortedList);
+
+/**
+ * Get the first element on the sorted list. This will NOT remove the element from the list.
+ *
+ * @param [in] parcSortedList A pointer to the `PARCSortedList` .
+ * @return The first element of the sorted list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcSortedList_GetFirst(PARCSortedList *parcSortedList);
+#endif // libparc_parc_SortedList_h
diff --git a/libparc/parc/algol/parc_OutputStream.c b/libparc/parc/algol/parc_OutputStream.c
new file mode 100755
index 00000000..d00c1f09
--- /dev/null
+++ b/libparc/parc/algol/parc_OutputStream.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_OutputStream.h>
+
+struct parc_output_stream {
+ void *instance;
+ const PARCOutputStreamInterface *interface;
+};
+
+static void
+_destroy(PARCOutputStream **streamPtr)
+{
+ PARCOutputStream *stream = *streamPtr;
+ (stream->interface->Release)((PARCOutputStream **) &stream->instance);
+}
+
+parcObject_ExtendPARCObject(PARCOutputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCOutputStream *
+parcOutputStream_Create(void *instance, const PARCOutputStreamInterface *interface)
+{
+ PARCOutputStream *result = parcObject_CreateInstance(PARCOutputStream);
+ result->instance = instance;
+ result->interface = interface;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcOutputStream, PARCOutputStream);
+
+parcObject_ImplementRelease(parcOutputStream, PARCOutputStream);
+
+size_t
+parcOutputStream_Write(PARCOutputStream *stream, PARCBuffer *buffer)
+{
+ return (stream->interface->Write)(stream->instance, buffer);
+}
+
+size_t
+parcOutputStream_WriteCStrings(PARCOutputStream *stream, ...)
+{
+ va_list ap;
+ va_start(ap, stream);
+
+ size_t result = 0;
+
+ for (char *string = va_arg(ap, char *); string != NULL; string = va_arg(ap, char *)) {
+ result += parcOutputStream_WriteCString(stream, string);
+ }
+
+ return result;
+}
+
+size_t
+parcOutputStream_WriteCString(PARCOutputStream *stream, const char *string)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString((char *) string);
+ size_t result = (stream->interface->Write)(stream->instance, buffer);
+ parcBuffer_Release(&buffer);
+ return result;
+}
diff --git a/libparc/parc/algol/parc_OutputStream.h b/libparc/parc/algol/parc_OutputStream.h
new file mode 100755
index 00000000..db0ba343
--- /dev/null
+++ b/libparc/parc/algol/parc_OutputStream.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_OutputStream.h
+ * @ingroup inputoutput
+ * @brief A polymophic interface to specific implementations of modules that implement the
+ * output stream capabilities.
+ *
+ *
+ *
+ */
+#ifndef libparc_parc_OutputStream_h
+#define libparc_parc_OutputStream_h
+
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_output_stream;
+typedef struct parc_output_stream PARCOutputStream;
+
+typedef struct parc_output_stream_interface {
+ size_t (*Write)(PARCOutputStream *stream, PARCBuffer *buffer);
+
+ PARCOutputStream *(*Acquire)(PARCOutputStream * stream);
+
+ void (*Release)(PARCOutputStream **streamPtr);
+} PARCOutputStreamInterface;
+
+/**
+ * Create an valid PARCOutputStream instance from the given pointers to a properly
+ * initialized `PARCOutputStreamInterface`
+ * and specific instance structure that will be supplied to the underlying interface.
+ *
+ * @param [in] instance A pointer to a `PARCObject` that will be the parameter to the functions specifed by @p interface.
+ * @param [in] interface A pointer to a `PARCOutputStreamInterface`.
+ *
+ * @return non-NULL A pointer to a valid PARCOutputStream instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * }
+ * @endcode
+ */
+PARCOutputStream *parcOutputStream_Create(void *instance, const PARCOutputStreamInterface *interface);
+
+/**
+ * Write the contents of the given `PARCBuffer` to the output stream.
+ *
+ * The position of the `PARCBuffer` will be set to its limit as a side-effect.
+ *
+ * @param [in] stream A pointer to a valid `PARCOutputStream` instance.
+ * @param [in] buffer A pointer to the `PARCBuffer` whose contents should be written to @p stream.
+ *
+ * @return The number of bytes written
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcOutputStream_Write(output, buffer);
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ */
+size_t parcOutputStream_Write(PARCOutputStream *stream, PARCBuffer *buffer);
+
+/**
+ * Write a nul-terminated C string to the given `PARCOutputStream`.
+ *
+ * @param [in] stream A pointer to a valid `PARCOutputStream` instance.
+ * @param [in] string A nul-terminated C string.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ *
+ * parcOutputStream_WriteCStrings(output, "Hello", " ", "World", NULL);
+ *
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ */
+size_t parcOutputStream_WriteCString(PARCOutputStream *stream, const char *string);
+
+/**
+ * Write one or more nul-terminated C strings to the given `PARCOutputStream`.
+ *
+ * @param [in] stream A pointer to a valid `PARCOutputStream` instance.
+ * @param [in] ... A NULL terminated variable argument list of nul-terminated C strings.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ *
+ * parcOutputStream_WriteCStrings(output, "Hello", " ", "World", NULL);
+ *
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ */
+size_t parcOutputStream_WriteCStrings(PARCOutputStream *stream, ...);
+
+/**
+ * Increase the number of references to a `PARCOutputStream`.
+ *
+ * Note that new `PARCOutputStream` is not created,
+ * only that the given `PARCOutputStream` reference count is incremented.
+ * Discard the reference by invoking `parcOutputStream_Release`.
+ *
+ * @param [in] stream A pointer to a `PARCOutputStream` instance.
+ *
+ * @return The input `PARCOutputStream` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcOutputStream_Write(output, buffer);
+ *
+ * PARCOutputStream *x = parcOutputStream_Acquire(output);
+ *
+ * parcBuffer_Release(&x);
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ * @see parcOutputStream_Release
+ */
+PARCOutputStream *parcOutputStream_Acquire(const PARCOutputStream *stream);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in] streamPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcOutputStream_Write(output, buffer);
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ * @see parcOutputStream_Acquire
+ * @see parcOutputStream_Create
+ */
+void parcOutputStream_Release(PARCOutputStream **streamPtr);
+#endif // libparc_parc_OutputStream_h
diff --git a/libparc/parc/algol/parc_PathName.c b/libparc/parc/algol/parc_PathName.c
new file mode 100755
index 00000000..e329ee88
--- /dev/null
+++ b/libparc/parc/algol/parc_PathName.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Deque.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#include <parc/algol/parc_PathName.h>
+
+struct parc_pathname {
+ bool isAbsolute;
+ PARCDeque *path;
+};
+
+static void
+_destroy(PARCPathName **pathNamePtr)
+{
+ PARCPathName *pathName = *pathNamePtr;
+
+ for (size_t i = 0; i < parcDeque_Size(pathName->path); i++) {
+ void *name = parcDeque_GetAtIndex(pathName->path, i);
+ parcMemory_Deallocate((void **) &name);
+ }
+ parcDeque_Release(&pathName->path);
+}
+
+static bool
+_pathNameSegmentEquals(const void *x, const void *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ return strcmp((char *) x, (char *) y) == 0;
+}
+
+static void *
+_pathNameSegmentCopy(const void *x)
+{
+ return parcMemory_StringDuplicate(x, strlen(x));
+}
+
+static const PARCObjectDescriptor parcPathNameSegment_ObjectInterface = {
+ .destroy = (PARCObjectDestroy *) NULL,
+ .copy = (PARCObjectCopy *) _pathNameSegmentCopy,
+ .toString = (PARCObjectToString *) NULL,
+ .equals = (PARCObjectEquals *) _pathNameSegmentEquals,
+ .compare = (PARCObjectCompare *) NULL
+};
+
+parcObject_ExtendPARCObject(PARCPathName, _destroy, parcPathName_Copy, parcPathName_ToString,
+ parcPathName_Equals, NULL, NULL, NULL);
+
+PARCPathName *
+parcPathName_ParseToLimit(size_t limit, const char path[limit])
+{
+ PARCPathName *result = parcPathName_Create();
+
+ if (limit > 0) {
+ size_t index = 0;
+
+ if (path[index] == '/') {
+ result->isAbsolute = true;
+ index++;
+ }
+ while (path[index] != 0 && index < limit) {
+ while (path[index] == '/' && index < limit) {
+ index++;
+ }
+ if (path[index] != 0 && index < limit) {
+ size_t segment = index;
+ while (path[index] != 0 && path[index] != '/' && index < limit) {
+ index++;
+ }
+
+ parcDeque_Append(result->path, parcMemory_StringDuplicate(&path[segment], index - segment));
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCPathName *
+parcPathName_Parse(const char *path)
+{
+ return parcPathName_ParseToLimit(strlen(path), path);
+}
+
+PARCPathName *
+parcPathName_Create(void)
+{
+ PARCPathName *result = parcObject_CreateInstance(PARCPathName);
+
+ result->isAbsolute = false;
+ result->path = parcDeque_CreateObjectInterface(&parcPathNameSegment_ObjectInterface);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcPathName, PARCPathName);
+
+parcObject_ImplementRelease(parcPathName, PARCPathName);
+
+PARCPathName *
+parcPathName_Copy(const PARCPathName *pathName)
+{
+ PARCPathName *result = parcObject_CreateInstance(PARCPathName);
+
+ result->isAbsolute = pathName->isAbsolute;
+ result->path = parcDeque_Copy(pathName->path);
+ return result;
+}
+
+bool
+parcPathName_Equals(const PARCPathName *x, const PARCPathName *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->isAbsolute == y->isAbsolute) {
+ return parcDeque_Equals(x->path, y->path);
+ }
+ return false;
+}
+
+bool
+parcPathName_IsAbsolute(const PARCPathName *pathName)
+{
+ return pathName->isAbsolute;
+}
+
+bool
+parcPathName_MakeAbsolute(PARCPathName *pathName, bool absolute)
+{
+ bool result = parcPathName_IsAbsolute(pathName);
+ pathName->isAbsolute = absolute;
+
+ return result;
+}
+
+PARCPathName *
+parcPathName_Prepend(PARCPathName *pathName, const char *name)
+{
+ parcDeque_Prepend(pathName->path, parcMemory_StringDuplicate(name, strlen(name)));
+ return pathName;
+}
+
+PARCPathName *
+parcPathName_Append(PARCPathName *pathName, const char *name)
+{
+ parcDeque_Append(pathName->path, parcMemory_StringDuplicate(name, strlen(name)));
+ return pathName;
+}
+
+char *
+parcPathName_GetAtIndex(const PARCPathName *pathName, size_t index)
+{
+ return (char *) parcDeque_GetAtIndex(pathName->path, index);
+}
+
+PARCPathName *
+parcPathName_Head(const PARCPathName *pathName, size_t size)
+{
+ PARCPathName *result = parcPathName_Create();
+ size_t maximum = parcPathName_Size(pathName) < size ? parcPathName_Size(pathName) : size;
+
+ for (size_t i = 0; i < maximum; i++) {
+ parcPathName_Append(result, parcPathName_GetAtIndex(pathName, i));
+ }
+
+ parcPathName_MakeAbsolute(result, parcPathName_IsAbsolute(pathName));
+
+ return result;
+}
+
+PARCPathName *
+parcPathName_Tail(const PARCPathName *pathName, size_t size)
+{
+ PARCPathName *result = parcPathName_Create();
+ if (size > parcPathName_Size(pathName)) {
+ size = parcPathName_Size(pathName);
+ }
+
+ for (size_t i = parcPathName_Size(pathName) - size; i < parcPathName_Size(pathName); i++) {
+ parcPathName_Prepend(result, parcPathName_GetAtIndex(pathName, i));
+ }
+
+ parcPathName_MakeAbsolute(result, false);
+
+ return result;
+}
+
+size_t
+parcPathName_Size(const PARCPathName *pathName)
+{
+ return parcDeque_Size(pathName->path);
+}
+
+PARCBufferComposer *
+parcPathName_BuildString(const PARCPathName *pathName, PARCBufferComposer *composer)
+{
+ char *separator = "/";
+
+ // an absolute path with no segments should just be '/'
+ if (parcPathName_IsAbsolute(pathName)) {
+ parcBufferComposer_PutString(composer, separator);
+ }
+
+ size_t length = parcDeque_Size(pathName->path);
+ if (length > 0) {
+ parcBufferComposer_PutString(composer, parcDeque_GetAtIndex(pathName->path, 0));
+ for (size_t i = 1; i < length; i++) {
+ parcBufferComposer_PutStrings(composer, separator, parcDeque_GetAtIndex(pathName->path, i), NULL);
+ }
+ }
+
+ return composer;
+}
+
+char *
+parcPathName_ToString(const PARCPathName *pathName)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcPathName_BuildString(pathName, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+void
+parcPathName_Display(const PARCPathName *pathName, int indentation)
+{
+ if (pathName == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCPathName@NULL\n");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCPathName@%p {\n", (void *) pathName);
+ parcDeque_Display(pathName->path, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+ }
+}
diff --git a/libparc/parc/algol/parc_PathName.h b/libparc/parc/algol/parc_PathName.h
new file mode 100644
index 00000000..d02f8ef5
--- /dev/null
+++ b/libparc/parc/algol/parc_PathName.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_PathName.h
+ * @ingroup inputoutput
+ * @brief Path Name Manipulation
+ *
+ */
+#ifndef libparc_parc_PathName_h
+#define libparc_parc_PathName_h
+
+struct parc_pathname;
+typedef struct parc_pathname PARCPathName;
+
+#include <parc/algol/parc_BufferComposer.h>
+
+/**
+ * Create an empty, relative, `PARCPathName`.
+ *
+ * @return A pointer to a `PARCPathName` instance.
+ *
+ * @see {@link parcPathName_MakeAbsolute}
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *result = parcPathName_Create();
+ * parcPathName_Destroy(&result);
+ * }
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Create(void);
+
+/**
+ * Parse a null-terminated C string as a `PARCPathName` limited to specific length.
+ * Components are separated by a single '/' character.
+ *
+ * @param [in] limit The limit to the length
+ * @param [in] path The string to parse
+ *
+ * @return A pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_ParseToLimit(size_t limit, const char *path);
+
+/**
+ * Parse a null-terminated C string as a `PARCPathName`
+ * Components are separated by a single '/' character.
+ *
+ * @param [in] path The string to be parsed
+ * @return A pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Parse(const char *path);
+
+/**
+ * Acquire a new reference to an instance of `PARCPathName`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] pathName The instance of `PARCPathName` to which to refer.
+ *
+ * @return The same value as the input parameter @p pathName
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCPathName *parcPathName_Acquire(const PARCPathName *pathName);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] pathNamePtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *pathName = parcPathName_Parse("/tmp/foo");
+ *
+ * parcPathName_Release(&pathName);
+ * }
+ * @endcode
+ */
+void parcPathName_Release(PARCPathName **pathNamePtr);
+
+/**
+ * Determine if two `PARCPathName` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCPathName` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcPathName_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcPathName_Equals(x, y)` must return true if and only if
+ * `parcPathName_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcPathName_Equals(x, y)` returns true and
+ * `parcPathName_Equals(y, z)` returns true,
+ * then `parcPathName_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcPathName_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcPathName_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a `PARCPathName` instance.
+ * @param [in] y A pointer to a `PARCPathName` instance.
+ *
+ * @return true `PARCPathName` x and y are equal.
+ * @return false `PARCPathName` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *a = parcPathName_Create();
+ * PARCPathName *b = parcPathName_Create();
+ *
+ * if (parcPathName_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ *
+ */
+bool parcPathName_Equals(const PARCPathName *x, const PARCPathName *y);
+
+/**
+ * Copy a pathName into a new instance of `PARCPathName`
+ *
+ * @param [in] pathName An instance of `PARCPathName` to be copied
+ *
+ * @return A new instance of `PARCPathName` that is a copy of @p pathName
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+PARCPathName *parcPathName_Copy(const PARCPathName *pathName);
+
+/**
+ * Return true if the instance of `PARCPathName` is absolute
+ *
+ * An absolute path name is a fully specified path starting at the root as the left-most segment.
+ * A relative path name is an incomplete path starting at an unspecified root.
+ *
+ * For example, an absolute UNIX file name path begins with a `/` character.
+ * `/foo/bar`, `/tmp/test` are both absolute path names.
+ *
+ * @param [in] pathName The instance of `PARCPathName` to test for absoluteness
+ * @return True is the path name is absolute, false otherwise.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcPathName_IsAbsolute(const PARCPathName *pathName);
+
+/**
+ * Make a `PARCPathName` absolute or relative.
+ *
+ * An absolute path name is a fully specified path starting at the root as the left-most segment.
+ * A relative path name is an incomplete path starting at an unspecified root.
+ *
+ * For example, an absolute UNIX file name path begins with a `/` character.
+ * `/foo/bar`, `/tmp/test` are both absolute path names.
+ *
+ *
+ * @param [in,out] pathName A pointer to a `PARCPathName` instance to be modified
+ * @param [in] absolute a flad as to whether the @p pathName should be set to absolute or relative; true indicates absolute
+ *
+ * @return true if the `PARCPathName` was previously an absolute path name.
+ * @return false if the `PARCPathName` was previously a relative path name.
+ *
+ * Example:
+ * @code
+ * {
+ * parcPathName_MakeAbsolute(pathName true)
+ * }
+ * @endcode
+ */
+bool parcPathName_MakeAbsolute(PARCPathName *pathName, bool absolute);
+
+/**
+ * Append a name segment to a `PARCPathName`
+ *
+ * The C string, `name` is copied.
+ *
+ * @param [in,out] pathName The instance of `PARCPathName` to modify
+ * @param [in] name A pointer to a null-terminated string. The contents are appended to the @p pathName.
+ *
+ * @return The input @p pathName
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCPathName *parcPathName_Append(PARCPathName *pathName, const char *name);
+
+/**
+ * Prepend a name segment to a `PARCPathName`
+ *
+ * The C string, `name` is copied.
+ *
+ * @param [in,out] pathName The instance of `PARCPathName` to modify
+ * @param [in] name A pointer to a null-terminated string. The contents are prepended to the @p pathName.
+ *
+ * @return The input @p pathName
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCPathName *parcPathName_Prepend(PARCPathName *pathName, const char *name);
+
+/**
+ * Create a new `PARCPathName` instance that consists of the head of an existing `PARCPathName`.
+ *
+ * If the original `PARCPathName` is an absolute path, the new `PARCPathName` will also be absolute.
+ * Otherwise, it will be a relative path.
+ *
+ * The new `PARCPathName` contains a copy of the requisite components of the orignal `PARCPathName`.
+ *
+ * @param [in] pathName The original `PARCPathName`
+ * @param [in] size The maximum number of path segments to include in the new `PARCPathName`.
+ *
+ * @return a Pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Head(const PARCPathName *pathName, size_t size);
+
+/**
+ * Create a new `PARCPathName` instance that consists of the tail of an existing `PARCPathName`.
+ *
+ * The new `PARCPathName` is a relative path and contains a copy of the requisite components of the orignal `PARCPathName`.
+ *
+ * @param [in] pathName The original `PARCPathName`
+ * @param [in] size The maximum number of path segments to include in the new `PARCPathName`.
+ *
+ * @return a Pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Tail(const PARCPathName *pathName, size_t size);
+
+/**
+ * Get a pointer to the null-terminated C string for the specified path name segment.
+ *
+ * @param [in] pathName A pointer to a `PARCPathName` instance.
+ * @param [in] index The index of the segment
+ *
+ * @return a pointer to the null-terminate C string for the specified path name segment
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+char *parcPathName_GetAtIndex(const PARCPathName *pathName, size_t index);
+
+/**
+ * Get the number of path segments in a `PARCPathName`.
+ *
+ * @param [in] pathName A pointer to a `PARCPathName` instance.
+ *
+ * @return The number of path segments in the `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+size_t parcPathName_Size(const PARCPathName *pathName);
+
+/**
+ * Append a representation of the specified instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] path A pointer to the `PARCPathName` whose representation should be added to the @p string.
+ * @param [in] string A pointer to the `PARCBufferComposer` to which to append the representation of @p path
+ *
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcPathName_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("Hello: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcPathName_BuildString(const PARCPathName *path, PARCBufferComposer *string);
+
+/**
+ * Produce a C string representation of the given `PARCPathName`.
+ *
+ * Produce an allocated, null-terminated string representation of the given `PARCPathName`.
+ * The result must be freed by the caller via the `parcMemory_Deallocate()` function.
+ *
+ * @param [in] pathName A pointer to the `PARCPathName` to convert to a `String`
+ *
+ * @return The string representation of @p pathName
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+char *parcPathName_ToString(const PARCPathName *pathName);
+
+/**
+ * Print a human readable representation of the given `PARCPathName`.
+ *
+ * @param [in] pathName A pointer to the instance of `PARCPathName` to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *instance = parcPathName_Create();
+ *
+ * parcPathName_Display(instance, 0);
+ *
+ * parcPathName_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcPathName_Display(const PARCPathName *pathName, int indentation);
+#endif // libparc_parc_PathName_h
diff --git a/libparc/parc/algol/parc_PriorityQueue.c b/libparc/parc/algol/parc_PriorityQueue.c
new file mode 100755
index 00000000..93744b2c
--- /dev/null
+++ b/libparc/parc/algol/parc_PriorityQueue.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Priority Queue implemented over a Binary Heap.
+ *
+ * A Binary Heap will have average insert of O(1) and delete of O(log n). The worst case
+ * is O(log n) for both. The average and worst case FindMin is O(1).
+ *
+ * The binary heap is implemented as a "0"-based array, so for node index n, the
+ * children are at 2n+1 and 2n+2. Its parent is at floor((n-1)/2).
+ *
+ * The Heap property is a[n] <= a[2n+1] and a[k] <= a[2k+2]. We need to move things around
+ * sufficiently for this property to remain true.
+ *
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_PriorityQueue.h>
+
+typedef struct heap_entry {
+ void *data;
+} HeapEntry;
+
+struct parc_priority_queue {
+ HeapEntry *array;
+ size_t capacity; // how many elements are allocated
+ size_t size; // how many elements are used
+
+ PARCPriorityQueueCompareTo *compare;
+ PARCPriorityQueueDestroyer *destroyer;
+};
+
+/**
+ * 0-based array indexing, so use 2n+1
+ */
+static size_t
+_leftChildIndex(size_t elementIndex)
+{
+ return 2 * elementIndex + 1;
+}
+
+/**
+ * 0-based array indexing, so use 2n+2
+ * IMPORTANT: This must be a larger index than the left child,
+ * as the TrickleDown algorithm assumes that if the right child exists so
+ * does the left child.
+ */
+static size_t
+_rightChildIndex(size_t elementIndex)
+{
+ return 2 * elementIndex + 2;
+}
+
+/**
+ * 0-based array indexing, so use (n-1)/2
+ */
+static size_t
+_parentIndex(size_t elementIndex)
+{
+ return (elementIndex - 1) / 2;
+}
+
+/**
+ * Exchange the data between two array locations
+ */
+static void
+_swap(PARCPriorityQueue *queue, size_t firstIndex, size_t secondIndex)
+{
+ void *firstData = queue->array[firstIndex].data;
+ queue->array[firstIndex].data = queue->array[secondIndex].data;
+ queue->array[secondIndex].data = firstData;
+}
+
+/**
+ * See parcPriorityQueue_TrickleDown for full details
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ *
+ * Case 2: Right child exists and r.value < n.value && l.value <= r.value
+ * In this case swap(n.index, l.index) and set n.index = l.index
+ * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant.
+ * 50 6
+ * / \ ===> / \
+ * 6 9 50 9
+ */
+static size_t
+_trickleRightChild(PARCPriorityQueue *queue, size_t elementIndex, size_t leftChildIndex, size_t rightChildIndex)
+{
+ if (queue->compare(queue->array[rightChildIndex].data, queue->array[elementIndex].data) < 0) {
+ if (queue->compare(queue->array[rightChildIndex].data, queue->array[leftChildIndex].data) < 0) {
+ // Case 1
+ _swap(queue, rightChildIndex, elementIndex);
+ elementIndex = rightChildIndex;
+ } else {
+ // Case 2
+ _swap(queue, leftChildIndex, elementIndex);
+ elementIndex = leftChildIndex;
+ }
+ }
+ return elementIndex;
+}
+
+/**
+ * See parcPriorityQueue_TrickleDown for full details
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ */
+static size_t
+_trickleLeftChild(PARCPriorityQueue *queue, size_t elementIndex, size_t leftChildIndex)
+{
+ if (queue->compare(queue->array[leftChildIndex].data, queue->array[elementIndex].data) < 0) {
+ // Case 3
+ _swap(queue, leftChildIndex, elementIndex);
+ elementIndex = leftChildIndex;
+ }
+ return elementIndex;
+}
+
+/**
+ * Moves an element down the heap until it satisfies the heap invariant.
+ *
+ * The value of node n must be less than or equal to both the left child and right child, if
+ * they exist. Here's the algorithm by example. Let r.value, l.value and n.value be the values
+ * of the right, left and node. Let r.index, l.index, and n.index be their indicies.
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ *
+ * Case 2: Right child exists and r.value < n.value && l.value <= r.value
+ * In this case swap(n.index, l.index) and set n.index = l.index
+ * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant.
+ * 50 6
+ * / \ ===> / \
+ * 6 9 50 9
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ *
+ * Case 4: No child exists or already satisfies invariant
+ * Done
+ * 50 50
+ * / \ ===> / \
+ * x x x x
+ * OR
+ * 4 4
+ * / \ ===> / \
+ * 9 6 9 6
+ *
+ *
+ * @param [in] queue The priority queue to manipulate
+ * @param [in] elementIndex The root element (n above) to trickle down
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_trickleDown(PARCPriorityQueue *queue, size_t elementIndex)
+{
+ bool finished = false;
+
+ while (!finished) {
+ size_t rightChildIndex = _rightChildIndex(elementIndex);
+ size_t leftChildIndex = _leftChildIndex(elementIndex);
+
+ if (rightChildIndex < queue->size) {
+ // Case 1 and Case 2
+ elementIndex = _trickleRightChild(queue, elementIndex, leftChildIndex, rightChildIndex);
+ } else if (leftChildIndex < queue->size) {
+ // Case 3
+ elementIndex = _trickleLeftChild(queue, elementIndex, leftChildIndex);
+ } else {
+ // Case 4, we're done
+ finished = true;
+ }
+ }
+}
+
+/**
+ * Move the item at elementIndex up the tree until it satisfies the invariant.
+ *
+ * This is used when we insert an element at the bottom of the heap. We bubble it up
+ * the heap until it satisfies the heap invariant (i.e. it's parent is less than or
+ * equal to it).
+ *
+ * @param [in] queue The priority queue to manipulate
+ * @param [in] elementIndex The 0-based index of the element to bubble up
+ */
+static void
+_bubbleUp(PARCPriorityQueue *queue, size_t elementIndex)
+{
+ size_t parentIndex = _parentIndex(elementIndex);
+ while (elementIndex > 0 && queue->compare(queue->array[elementIndex].data, queue->array[parentIndex].data) < 0) {
+ _swap(queue, elementIndex, parentIndex);
+ // now move up the ladder
+ elementIndex = parentIndex;
+ parentIndex = _parentIndex(elementIndex);
+ }
+
+ // At this point, it is either at the top (elementIndex = 0) or statisfies the heap invariant.
+}
+
+/**
+ * Add more elements to the backing aray
+ *
+ * Expand the array capacity. We use a fixed x2 expansion each time, though this might not
+ * be desirable when the capacity gets large.
+ *
+ * @param [in] queue The priority queue to manipulate
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_expand(PARCPriorityQueue *queue)
+{
+ queue->capacity *= 2;
+ queue->array = parcMemory_Reallocate(queue->array, sizeof(HeapEntry) * queue->capacity);
+}
+
+// ================================
+// Public API
+
+void
+parcPriorityQueue_ParcFreeDestroyer(void **elementPtr)
+{
+ assertNotNull(elementPtr, "Double pointer must be non-null");
+ assertNotNull(*elementPtr, "Double pointer must dereference to non-null");
+ void *element = *elementPtr;
+ parcMemory_Deallocate((void **) &element);
+ *elementPtr = NULL;
+}
+
+int
+parcPriorityQueue_Uint64CompareTo(const void *a, const void *b)
+{
+ uint64_t value_a = *((uint64_t *) a);
+ uint64_t value_b = *((uint64_t *) b);
+ if (value_a < value_b) {
+ return -1;
+ } else if (value_a > value_b) {
+ return +1;
+ }
+ return 0;
+}
+
+PARCPriorityQueue *
+parcPriorityQueue_Create(PARCPriorityQueueCompareTo *compare, PARCPriorityQueueDestroyer *destroyer)
+{
+ assertNotNull(compare, "Parameter compare must be non-null");
+
+ size_t initialSize = 128;
+ PARCPriorityQueue *queue = parcMemory_AllocateAndClear(sizeof(PARCPriorityQueue));
+ assertNotNull(queue, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCPriorityQueue));
+ queue->array = parcMemory_AllocateAndClear(sizeof(HeapEntry) * initialSize);
+ assertNotNull(queue->array, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(HeapEntry) * initialSize);
+ queue->capacity = initialSize;
+ queue->size = 0;
+ queue->compare = compare;
+ queue->destroyer = destroyer;
+
+ return queue;
+}
+
+void
+parcPriorityQueue_Destroy(PARCPriorityQueue **queuePtr)
+{
+ assertNotNull(queuePtr, "Double pointer must be non-null");
+ assertNotNull(*queuePtr, "Double pointer must dereference to non-null");
+ PARCPriorityQueue *queue = *queuePtr;
+ parcPriorityQueue_Clear(queue);
+ parcMemory_Deallocate((void **) &(queue->array));
+ parcMemory_Deallocate((void **) &queue);
+ *queuePtr = NULL;
+}
+
+bool
+parcPriorityQueue_Add(PARCPriorityQueue *queue, void *data)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ assertNotNull(data, "Parameter data must be non-null");
+
+ if (queue->size + 1 > queue->capacity) {
+ _expand(queue);
+ }
+
+ // insert at the end of the array
+ queue->array[queue->size].data = data;
+
+ // increment the size before calling bubble up so invariants are true (i.e.
+ // the index we're giving to BubbleUp is within the array size.
+ queue->size++;
+ _bubbleUp(queue, queue->size - 1);
+
+ // we always allow duplicates, so always return true
+ return true;
+}
+
+void
+parcPriorityQueue_Clear(PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ if (queue->destroyer != NULL) {
+ for (size_t i = 0; i < queue->size; i++) {
+ queue->destroyer(&queue->array[i].data);
+ }
+ }
+
+ queue->size = 0;
+}
+
+void *
+parcPriorityQueue_Peek(PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ if (queue->size > 0) {
+ return queue->array[0].data;
+ }
+ return NULL;
+}
+
+void *
+parcPriorityQueue_Poll(PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ if (queue->size > 0) {
+ void *data = queue->array[0].data;
+
+ queue->size--;
+
+ // if size == 1, then this is a no-op
+ queue->array[0].data = queue->array[queue->size].data;
+
+ // make sure the head satisifies the heap invariant
+ _trickleDown(queue, 0);
+
+ return data;
+ }
+
+ return NULL;
+}
+
+size_t
+parcPriorityQueue_Size(const PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ return queue->size;
+}
diff --git a/libparc/parc/algol/parc_PriorityQueue.h b/libparc/parc/algol/parc_PriorityQueue.h
new file mode 100755
index 00000000..45a6ffab
--- /dev/null
+++ b/libparc/parc/algol/parc_PriorityQueue.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_PriorityQueue.h
+ * @ingroup datastructures
+ * @brief A priority queue (heap), where the top item is the minimum by the sort function.
+ *
+ * The user provides a sort function and the top item will be the minimum
+ * as per the < relation.
+ *
+ */
+
+#ifndef libparc_parc_PriorityQueue_h
+#define libparc_parc_PriorityQueue_h
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+struct parc_priority_queue;
+typedef struct parc_priority_queue PARCPriorityQueue;
+
+typedef int (PARCPriorityQueueCompareTo)(const void *a, const void *b);
+typedef void (PARCPriorityQueueDestroyer)(void **elementPtr);
+
+/**
+ * Calls {@link parcMemory_Deallocate} to free the element
+ *
+ * A simple destroyer that only uses {@link parcMemory_Deallocate}.
+ *
+ * @param [in,out] elementPtr Double pointer to data item, will be NULL'd
+ *
+ * Example:
+ * @code
+ *
+ * PARCPriorityQueue *q = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ * uint64_t *objectid = parcMemory_Allocate(sizeof(uint64_t));
+ * objectid = 100;
+ *
+ * // this will use parcPriorityQueue_Uint64CompareTo sort order
+ * parcPriorityQueue_Add(q, objectid);
+ *
+ * // this will use the ParcFreeDestroyer
+ * parcPriorityQueue_Destroy(&q);
+ * @endcode
+ */
+void parcPriorityQueue_ParcFreeDestroyer(void **elementPtr);
+
+/**
+ * Treats the parameters as `uint64_t` pointers and compares them via natural sort order.
+ *
+ * Treats the parameters as `uint64_t` pointers and compares them via natural sort order.
+ * Obeys standared CompareTo semantics.
+ *
+ * @param [in] a uint64_t pointer
+ * @param [in] b uint64_t pointer
+ *
+ * @return -1 if a < b
+ * @return 0 if a == b
+ * @return +1 if a > b
+ *
+ * Example:
+ * @code
+ *
+ * PARCPriorityQueue *q = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ * uint64_t *objectid = parcMemory_Allocate(sizeof(uint64_t));
+ * objectid = 100;
+ *
+ * // this will use parcPriorityQueue_Uint64CompareTo sort order
+ * parcPriorityQueue_Add(q, objectid);
+ *
+ * // this will use the ParcFreeDestroyer
+ * parcPriorityQueue_Destroy(&q);
+ * @endcode
+ */
+int parcPriorityQueue_Uint64CompareTo(const void *a, const void *b);
+
+
+/**
+ * Creates a priority queue with a given sort function.
+ *
+ * The sort function defines the ordering of the Priorty Queue. The minimum element
+ * will always be the head of the queue.
+ *
+ * The destroyer is called on data elements from {@link parcPriorityQueue_Clear()} and
+ * {@link parcPriorityQueue_Destroy()}. You may use {@linkparcPriorityQueue_ParcFreeDestroyer()} for
+ * elements that can be freed by only calling {@link parcMemory_Deallocate}.
+ *
+ * @param [in] compare Defines the sort order of the priority queue
+ * @param [in] destroyer Called for Clear and Destroy operations, may be NULL.
+ *
+ * @return non-null A pointer to a `PARCPriorityQueue`
+ *
+ * Example:
+ * @code
+ * PARCPriorityQueue *q = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ * uint64_t *objectid = parcMemory_Allocate(sizeof(uint64_t));
+ * objectid = 100;
+ *
+ * // this will use parcPriorityQueue_Uint64CompareTo sort order
+ * parcPriorityQueue_Add(q, objectid);
+ *
+ * // this will use the ParcFreeDestroyer
+ * parcPriorityQueue_Destroy(&q);
+ * @endcode
+ */
+PARCPriorityQueue *parcPriorityQueue_Create(PARCPriorityQueueCompareTo *compare, PARCPriorityQueueDestroyer *destroyer);
+
+
+/**
+ * Destroy the queue and free remaining elements.
+ *
+ * Destroys the queue. If the destroyer was set in Create, then it will be called
+ * on all the remaining elements.
+ *
+ * @param [in,out] queuePtr Double pointer to allocated queue.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcPriorityQueue_Destroy(PARCPriorityQueue **queuePtr);
+
+/**
+ * Add an element to the priority queue, returning true if changed
+ *
+ * A "duplicate" is a data item that compares as equal to another item. The priority
+ * queue supports duplicates. It is not stable in regard to the ordering of duplicates.
+ * Because it supports duplicates, Add will always return true.
+ *
+ * The priority queue is unbounded.
+ *
+ * @param [in,out] queue The queue to modify
+ * @param [in] data The data to add to the queue, which must be comparable and not NULL
+ *
+ * @return true The data structure was modified by adding the new value
+ * @return false The data structure was not modified
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcPriorityQueue_Add(PARCPriorityQueue *queue, void *data);
+
+/**
+ * Removes all elements, calling the data structure's destroyer on each
+ *
+ * Remvoes all elements. If the data structure's destroyer is non-NULL, it will be called
+ * on each element.
+ *
+ * @param [in,out] queue The queue to modify
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcPriorityQueue_Clear(PARCPriorityQueue *queue);
+
+/**
+ * Returns the head element, but does not remove it.
+ *
+ * Returns the head element. The data structure is not modified. If the
+ * priority queue is empty, will return NULL.
+ *
+ * @param [in] queue The `PARCPriorityQueue` to query.
+ *
+ * @return non-null The head element
+ * @return null The queue is empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcPriorityQueue_Peek(PARCPriorityQueue *queue);
+
+/**
+ * Removes the head element from the queue and returns it.
+ *
+ * Removes the head element from the queue and returns it. If the queue is empty,
+ * it returns NULL.
+ *
+ * @param [in,out] queue The queue to query and modify.
+ *
+ * @return non-null The head element
+ * @return null The queue is empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcPriorityQueue_Poll(PARCPriorityQueue *queue);
+
+/**
+ * Returns the number of elements in the queue.
+ *
+ * @param [in] queue The `PARCPriorityQueue` to query.
+ *
+ * @return number The number of elements in the queue.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcPriorityQueue_Size(const PARCPriorityQueue *queue);
+#endif // libparc_parc_PriorityQueue_h
diff --git a/libparc/parc/algol/parc_Properties.c b/libparc/parc/algol/parc_Properties.c
new file mode 100644
index 00000000..19aea290
--- /dev/null
+++ b/libparc/parc/algol/parc_Properties.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include "parc_Properties.h"
+
+struct PARCProperties {
+ PARCHashMap *properties;
+};
+
+static void
+_parcProperties_Finalize(PARCProperties **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCProperties pointer.");
+ PARCProperties *instance = *instancePtr;
+
+ parcProperties_OptionalAssertValid(instance);
+
+ parcHashMap_Release(&instance->properties);
+}
+
+parcObject_ImplementAcquire(parcProperties, PARCProperties);
+
+parcObject_ImplementRelease(parcProperties, PARCProperties);
+
+parcObject_ExtendPARCObject(PARCProperties, _parcProperties_Finalize, parcProperties_Copy, parcProperties_ToString, parcProperties_Equals, parcProperties_Compare, parcProperties_HashCode, parcProperties_ToJSON);
+
+
+void
+parcProperties_AssertValid(const PARCProperties *instance)
+{
+ assertTrue(parcProperties_IsValid(instance),
+ "PARCProperties is not valid.");
+}
+
+PARCProperties *
+parcProperties_Create(void)
+{
+ PARCProperties *result = parcObject_CreateInstance(PARCProperties);
+
+ if (result != NULL) {
+ result->properties = parcHashMap_Create();
+ }
+
+ return result;
+}
+
+int
+parcProperties_Compare(const PARCProperties *instance, const PARCProperties *other)
+{
+ int result = 0;
+
+
+ return result;
+}
+
+PARCProperties *
+parcProperties_Copy(const PARCProperties *original)
+{
+ PARCProperties *result = parcObject_CreateInstance(PARCProperties);
+
+ if (result != NULL) {
+ result->properties = parcHashMap_Copy(original->properties);
+ }
+
+ return result;
+}
+
+void
+parcProperties_Display(const PARCProperties *properties, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCProperties@%p {", properties);
+ trapCannotObtainLockIf(parcHashMap_Lock(properties->properties) == false, "Cannot lock PARCProperties object.");
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(properties->properties);
+ while (parcIterator_HasNext(iterator)) {
+ char *key = parcBuffer_ToString(parcIterator_Next(iterator));
+ const char *value = parcProperties_GetProperty(properties, key);
+ parcDisplayIndented_PrintLine(indentation + 1, "%s=%s", key, value);
+
+ parcMemory_Deallocate(&key);
+ }
+
+ parcIterator_Release(&iterator);
+
+ parcHashMap_Unlock(properties->properties);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcProperties_Equals(const PARCProperties *x, const PARCProperties *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ return parcHashMap_Equals(x->properties, y->properties);
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcProperties_HashCode(const PARCProperties *instance)
+{
+ return parcHashMap_HashCode(instance->properties);
+}
+
+bool
+parcProperties_IsValid(const PARCProperties *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcProperties_ToJSON(const PARCProperties *properties)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ trapCannotObtainLockIf(parcHashMap_Lock(properties->properties) == false, "Cannot lock PARCProperties object.");
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(properties->properties);
+ while (parcIterator_HasNext(iterator)) {
+ char *key = parcBuffer_ToString(parcIterator_Next(iterator));
+ const char *value = parcProperties_GetProperty(properties, key);
+ parcJSON_AddString(result, key, value);
+ parcMemory_Deallocate(&key);
+ }
+
+ parcIterator_Release(&iterator);
+
+ parcHashMap_Unlock(properties->properties);
+ return result;
+}
+
+PARCBufferComposer *
+parcProperties_BuildString(const PARCProperties *properties, PARCBufferComposer *composer)
+{
+ trapCannotObtainLockIf(parcHashMap_Lock(properties->properties) == false, "Cannot lock PARCProperties object.");
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(properties->properties);
+ while (parcIterator_HasNext(iterator)) {
+ char *key = parcBuffer_ToString(parcIterator_Next(iterator));
+ const char *value = parcProperties_GetProperty(properties, key);
+ parcBufferComposer_PutStrings(composer, key, "=", value, "\n", NULL);
+ parcMemory_Deallocate(&key);
+ }
+
+ parcIterator_Release(&iterator);
+
+ parcHashMap_Unlock(properties->properties);
+ return composer;
+}
+
+char *
+parcProperties_ToString(const PARCProperties *properties)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcProperties_BuildString(properties, composer);
+ char *result = parcBufferComposer_ToString(composer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+void
+parcProperties_SetParsedProperty(PARCProperties *properties, char *string)
+{
+ char *equals = strchr(string, '=');
+ *equals++ = 0;
+
+ parcProperties_SetProperty(properties, string, equals);
+}
+
+bool
+parcProperties_SetProperty(PARCProperties *properties, const char *name, const char *string)
+{
+ bool result = false;
+
+ PARCBuffer *key = parcBuffer_AllocateCString(name);
+ PARCBuffer *value = parcBuffer_AllocateCString(string);
+
+ parcHashMap_Put(properties->properties, key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ return result;
+}
+
+const char *
+parcProperties_GetProperty(const PARCProperties *properties, const char *name)
+{
+ char *result = NULL;
+
+ PARCBuffer *key = parcBuffer_AllocateCString(name);
+ PARCBuffer *value = (PARCBuffer *) parcHashMap_Get(properties->properties, key);
+ if (value != NULL) {
+ result = parcBuffer_Overlay(value, 0);
+ }
+
+ parcBuffer_Release(&key);
+ return result;
+}
+
+const char *
+parcProperties_GetPropertyDefault(const PARCProperties *properties, const char *restrict name, const char *restrict defaultValue)
+{
+ char *result = (char *) defaultValue;
+
+ PARCBuffer *key = parcBuffer_AllocateCString(name);
+ PARCBuffer *value = (PARCBuffer *) parcHashMap_Get(properties->properties, key);
+ if (value != NULL) {
+ result = parcBuffer_Overlay(value, 0);
+ }
+
+ parcBuffer_Release(&key);
+ return result;
+}
+
+bool
+parcProperties_GetAsBoolean(const PARCProperties *properties, const char *name, bool defaultValue)
+{
+ bool result = defaultValue;
+
+ const char *value = parcProperties_GetProperty(properties, name);
+ if (value != NULL) {
+ if (strcmp(value, "true") == 0) {
+ result = true;
+ } else {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+int64_t
+parcProperties_GetAsInteger(const PARCProperties *properties, const char *name, int64_t defaultValue)
+{
+ int64_t result = defaultValue;
+
+ const char *value = parcProperties_GetProperty(properties, name);
+ if (value != NULL) {
+ result = strtol(value, NULL, 10);
+ }
+
+ return result;
+}
+
+typedef struct {
+ PARCBuffer *element;
+ PARCIterator *hashMapIterator;
+} _PARCPropertiesIterator;
+
+static _PARCPropertiesIterator *
+_parcPropertiesIterator_Init(const PARCProperties *object)
+{
+ _PARCPropertiesIterator *state = parcMemory_AllocateAndClear(sizeof(_PARCPropertiesIterator));
+ state->hashMapIterator = parcHashMap_CreateKeyIterator(object->properties);
+ return state;
+}
+
+static bool
+_parcPropertiesIterator_HasNext(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ return parcIterator_HasNext(state->hashMapIterator);
+}
+
+static _PARCPropertiesIterator *
+_parcPropertiesIterator_Next(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ state->element = (PARCBuffer *) parcIterator_Next(state->hashMapIterator);
+ return state;
+}
+
+static void
+_parcPropertiesIterator_Remove(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator **state)
+{
+ parcIterator_Remove((*state)->hashMapIterator);
+}
+
+static char *
+_parcPropertiesIterator_Element(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ return parcBuffer_Overlay(state->element, 0);
+}
+
+static void
+_parcPropertiesIterator_Fini(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ parcIterator_Release(&state->hashMapIterator);
+ parcMemory_Deallocate(&state);
+}
+
+PARCIterator *
+parcProperties_CreateIterator(const PARCProperties *properties)
+{
+ PARCIterator *iterator = parcIterator_Create((PARCObject *) properties,
+ (void *(*)(PARCObject *))_parcPropertiesIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcPropertiesIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcPropertiesIterator_Next,
+ (void (*)(PARCObject *, void **))_parcPropertiesIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcPropertiesIterator_Element,
+ (void (*)(PARCObject *, void *))_parcPropertiesIterator_Fini,
+ NULL);
+
+ return iterator;
+}
diff --git a/libparc/parc/algol/parc_Properties.h b/libparc/parc/algol/parc_Properties.h
new file mode 100644
index 00000000..6cca4d87
--- /dev/null
+++ b/libparc/parc/algol/parc_Properties.h
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Properties.h
+ * @ingroup types
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Properties
+#define PARCLibrary_parc_Properties
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct PARCProperties;
+typedef struct PARCProperties PARCProperties;
+
+/**
+ * Increase the number of references to a `PARCProperties` instance.
+ *
+ * Note that new `PARCProperties` is not created,
+ * only that the given `PARCProperties` reference count is incremented.
+ * Discard the reference by invoking `parcProperties_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * PARCProperties *b = parcProperties_Acquire();
+ *
+ * parcProperties_Release(&a);
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ */
+PARCProperties *parcProperties_Acquire(const PARCProperties *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcProperties_OptionalAssertValid(_instance_)
+#else
+# define parcProperties_OptionalAssertValid(_instance_) parcProperties_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCProperties` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ */
+void parcProperties_AssertValid(const PARCProperties *instance);
+
+/**
+ * Create an instance of PARCProperties
+ *
+ * @return non-NULL A pointer to a valid PARCProperties instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+PARCProperties *parcProperties_Create(void);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ * @param [in] other A pointer to a valid PARCProperties instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ * PARCProperties *b = parcProperties_Create();
+ *
+ * if (parcProperties_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcProperties_Release(&a);
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcProperties_Equals
+ */
+int parcProperties_Compare(const PARCProperties *instance, const PARCProperties *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCProperties instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCProperties` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * PARCProperties *copy = parcProperties_Copy(&b);
+ *
+ * parcProperties_Release(&b);
+ * parcProperties_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCProperties *parcProperties_Copy(const PARCProperties *original);
+
+/**
+ * Print a human readable representation of the given `PARCProperties`.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_Display(a, 0);
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+void parcProperties_Display(const PARCProperties *instance, int indentation);
+
+/**
+ * Determine if two `PARCProperties` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCProperties` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcProperties_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcProperties_Equals(x, y)` must return true if and only if
+ * `parcProperties_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcProperties_Equals(x, y)` returns true and
+ * `parcProperties_Equals(y, z)` returns true,
+ * then `parcProperties_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcProperties_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcProperties_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCProperties instance.
+ * @param [in] y A pointer to a valid PARCProperties instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ * PARCProperties *b = parcProperties_Create();
+ *
+ * if (parcProperties_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcProperties_Release(&a);
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ * @see parcProperties_HashCode
+ */
+bool parcProperties_Equals(const PARCProperties *x, const PARCProperties *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcProperties_Equals} method,
+ * then calling the {@link parcProperties_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcProperties_Equals} function,
+ * then calling the `parcProperties_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * uint32_t hashValue = parcProperties_HashCode(buffer);
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcProperties_HashCode(const PARCProperties *instance);
+
+/**
+ * Determine if an instance of `PARCProperties` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * if (parcProperties_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcProperties_IsValid(const PARCProperties *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCProperties` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+void parcProperties_Release(PARCProperties **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * PARCJSON *json = parcProperties_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcProperties_ToJSON(const PARCProperties *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCProperties`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * char *string = parcProperties_ToString(a);
+ *
+ * parcProperties_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcProperties_Display
+ */
+char *parcProperties_ToString(const PARCProperties *instance);
+
+/**
+ * Append a representation of the specified `PARCProperties` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] properties A pointer to a `PARCProperties` instance whose representation should be appended to the @p composer.
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance to be modified.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcProperties_BuildString(instance, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcProperties_BuildString(const PARCProperties *properties, PARCBufferComposer *composer);
+
+/**
+ * Set the named property to @p value.
+ *
+ *
+ * @param [in] properties A pointer to a valid `PARCProperties` instance.
+ * @param [in] name A pointer to a nul-terminate, C string name for the property.
+ * @param [in] value A A pointer to a nul-terminate, C string name for the value of the property.
+ *
+ * @return true <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcProperties_SetProperty(PARCProperties *properties, const char *name, const char *value);
+
+
+void parcProperties_SetParsedProperty(PARCProperties *properties, char *string);
+
+/**
+ * Get the string value of the named property.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties intance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ *
+ * @return non-NULL A nul-terminated C string containing the value of the named property.
+ * @return NULL The property was not found.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcProperties_GetProperty(const PARCProperties *properties, const char *restrict name);
+
+/**
+ * Return the string value of the named property, if present.
+ * Otherwise return the default value.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties instance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ * @param [in] defaultValue A pointer to a nul-terminated, C string containing the name of the property.
+ *
+ * @return non-NULL A nul-terminated C string containing the value of the named property.
+ * @return NULL The property was not found, and the default property was NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcProperties_GetPropertyDefault(const PARCProperties *properties, const char *restrict name, const char *restrict defaultValue);
+
+/**
+ * Return the boolean value of the named property, if present.
+ * Otherwise return the default value.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties instance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ * @param [in] defaultValue The default boolean value.
+ *
+ * @return true A the property is set to true.
+ * @return false The property is either not present, or is not set to true.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcProperties_GetAsBoolean(const PARCProperties *properties, const char *name, bool defaultValue);
+
+/**
+ * Return the integer value of the named property, if present.
+ * Otherwise return the default value.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties instance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ * @param [in] defaultValue The default integer value.
+ *
+ * @return The integer value of the named property.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int64_t parcProperties_GetAsInteger(const PARCProperties *properties, const char *name, int64_t defaultValue);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the given PARCProperties.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] list A pointer to a valid `PARCProperties`.
+ *
+ * @see parcIterator_Release
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcLinkedList_CreateIterator(hashMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcProperties_CreateIterator(const PARCProperties *properties);
+#endif
diff --git a/libparc/parc/algol/parc_RandomAccessFile.c b/libparc/parc/algol/parc_RandomAccessFile.c
new file mode 100755
index 00000000..65bff1d1
--- /dev/null
+++ b/libparc/parc/algol/parc_RandomAccessFile.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_RandomAccessFile.h>
+
+#include <stdio.h>
+
+struct PARCRandomAccessFile {
+ char *fname;
+ FILE *fhandle;
+};
+
+static void
+_parcRandomAccessFile_Finalize(PARCRandomAccessFile **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCRandomAccessFile pointer.");
+ PARCRandomAccessFile *instance = *instancePtr;
+ if (instance->fhandle != NULL) {
+ fclose(instance->fhandle);
+ }
+ if (instance->fname != NULL) {
+ parcMemory_Deallocate(&instance->fname);
+ }
+}
+
+parcObject_ImplementAcquire(parcRandomAccessFile, PARCRandomAccessFile);
+
+parcObject_ImplementRelease(parcRandomAccessFile, PARCRandomAccessFile);
+
+parcObject_ExtendPARCObject(PARCRandomAccessFile, _parcRandomAccessFile_Finalize, NULL,
+ parcRandomAccessFile_ToString, parcRandomAccessFile_Equals, NULL,
+ parcRandomAccessFile_HashCode, parcRandomAccessFile_ToJSON);
+
+
+void
+parcRandomAccessFile_AssertValid(const PARCRandomAccessFile *instance)
+{
+ assertTrue(parcRandomAccessFile_IsValid(instance),
+ "PARCRandomAccessFile is not valid.");
+}
+
+void
+parcRandomAccessFile_Display(const PARCRandomAccessFile *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCRandomAccessFile@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "File: %s", instance->fname);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+PARCHashCode
+parcRandomAccessFile_HashCode(const PARCRandomAccessFile *instance)
+{
+ return parcHashCode_Hash((uint8_t *) instance->fname, strlen(instance->fname));
+}
+
+bool
+parcRandomAccessFile_Equals(const PARCRandomAccessFile *x, const PARCRandomAccessFile *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (strcmp(x->fname, y->fname) == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+bool
+parcRandomAccessFile_IsValid(const PARCRandomAccessFile *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = instance->fhandle != NULL;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcRandomAccessFile_ToJSON(const PARCRandomAccessFile *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ parcJSON_AddString(result, "fname", instance->fname);
+ }
+
+ return result;
+}
+
+char *
+parcRandomAccessFile_ToString(const PARCRandomAccessFile *instance)
+{
+ char *result = parcMemory_Format("PARCRandomAccessFile[%s]@%p\n", instance->fname, instance);
+ return result;
+}
+
+PARCRandomAccessFile *
+parcRandomAccessFile_Open(PARCFile *file)
+{
+ PARCRandomAccessFile *handle = parcObject_CreateAndClearInstance(PARCRandomAccessFile);
+ if (handle != NULL) {
+ char *fname = parcFile_ToString(file);
+ handle->fhandle = fopen(fname, "r+");
+ handle->fname = parcMemory_StringDuplicate(fname, strlen(fname));
+ parcMemory_Deallocate(&fname);
+ }
+ return handle;
+}
+
+bool
+parcRandomAccessFile_Close(PARCRandomAccessFile *fileHandle)
+{
+ assertNotNull(fileHandle->fhandle, "Can't fclose a null pointer. How did they get one anyway?");
+ bool result = fclose(fileHandle->fhandle) == 0;
+ fileHandle->fhandle = NULL;
+ parcMemory_Deallocate(&fileHandle->fname);
+ fileHandle->fname = NULL;
+ return result;
+}
+
+// read (count * size) bytes into the provided buffer, and return the number of bytes actually read
+size_t
+parcRandomAccessFile_Read(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t numBytes = fread(parcBuffer_Overlay(buffer, length), 1, length, fileHandle->fhandle);
+ return numBytes;
+}
+
+// write (count * size) bytes from `buffer` to the file, and return the number of bytes actually written
+size_t
+parcRandomAccessFile_Write(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t numBytes = fwrite(parcBuffer_Overlay(buffer, length), 1, length, fileHandle->fhandle);
+ return numBytes;
+}
+
+size_t
+parcRandomAccessFile_Seek(PARCRandomAccessFile *fileHandle, long offset, PARCRandomAccessFilePosition position)
+{
+ size_t result = 0;
+ switch (position) {
+ case PARCRandomAccessFilePosition_Start:
+ result = fseek(fileHandle->fhandle, offset, SEEK_SET); // beginning of the file
+ break;
+ case PARCRandomAccessFilePosition_Current:
+ result = fseek(fileHandle->fhandle, offset, SEEK_CUR); // current offset
+ break;
+ case PARCRandomAccessFilePosition_End:
+ result = fseek(fileHandle->fhandle, offset, SEEK_END); // end of the file
+ break;
+ default:
+ assertTrue(false, "Invalid position %d", position);
+ }
+ return result;
+}
diff --git a/libparc/parc/algol/parc_RandomAccessFile.h b/libparc/parc/algol/parc_RandomAccessFile.h
new file mode 100755
index 00000000..f4f20150
--- /dev/null
+++ b/libparc/parc/algol/parc_RandomAccessFile.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_RandomAccessFile.h
+ * @ingroup inputoutput
+ * @brief A wrapper that provides random access to a file.
+ *
+ */
+#ifndef PARCLibrary_RandomAccessFile
+#define PARCLibrary_RandomAccessFile
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_File.h>
+
+struct PARCRandomAccessFile;
+typedef struct PARCRandomAccessFile PARCRandomAccessFile;
+
+typedef enum {
+ PARCRandomAccessFilePosition_Start,
+ PARCRandomAccessFilePosition_End,
+ PARCRandomAccessFilePosition_Current
+} PARCRandomAccessFilePosition;
+
+/**
+ * Increase the number of references to a `PARCRandomAccessFile` instance.
+ *
+ * Note that new `PARCRandomAccessFile` is not created,
+ * only that the given `PARCRandomAccessFile` reference count is incremented.
+ * Discard the reference by invoking `parcRandomAccessFile_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * PARCRandomAccessFile *b = parcRandomAccessFile_Acquire();
+ *
+ * parcRandomAccessFile_Release(&a);
+ * parcRandomAccessFile_Release(&b);
+ * }
+ * @endcode
+ */
+PARCRandomAccessFile *parcRandomAccessFile_Acquire(const PARCRandomAccessFile *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcRandomAccessFile_OptionalAssertValid(_instance_)
+#else
+# define parcRandomAccessFile_OptionalAssertValid(_instance_) parcRandomAccessFile_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCRandomAccessFile` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * parcRandomAccessFile_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcRandomAccessFile_Release(&b);
+ * }
+ * @endcode
+ */
+void parcRandomAccessFile_AssertValid(const PARCRandomAccessFile *instance);
+
+/**
+ * Print a human readable representation of the given `PARCRandomAccessFile`.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * parcRandomAccessFile_Display(a, 0);
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+void parcRandomAccessFile_Display(const PARCRandomAccessFile *instance, int indentation);
+
+/**
+ * Determine if two `PARCRandomAccessFile` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCRandomAccessFile` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcRandomAccessFile_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcRandomAccessFile_Equals(x, y)` must return true if and only if
+ * `parcRandomAccessFile_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcRandomAccessFile_Equals(x, y)` returns true and
+ * `parcRandomAccessFile_Equals(y, z)` returns true,
+ * then `parcRandomAccessFile_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcRandomAccessFile_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcRandomAccessFile_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCRandomAccessFile instance.
+ * @param [in] y A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ * PARCRandomAccessFile *b = parcRandomAccessFile_Open(..);
+ *
+ * if (parcRandomAccessFile_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcRandomAccessFile_Release(&a);
+ * parcRandomAccessFile_Release(&b);
+ * }
+ * @endcode
+ * @see parcRandomAccessFile_HashCode
+ */
+bool parcRandomAccessFile_Equals(const PARCRandomAccessFile *x, const PARCRandomAccessFile *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcRandomAccessFile_Equals} method,
+ * then calling the {@link parcRandomAccessFile_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcRandomAccessFile_Equals} function,
+ * then calling the `parcRandomAccessFile_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open..();
+ *
+ * PARCHashCode hashValue = parcRandomAccessFile_HashCode(buffer);
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcRandomAccessFile_HashCode(const PARCRandomAccessFile *instance);
+
+/**
+ * Determine if an instance of `PARCRandomAccessFile` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * if (parcRandomAccessFile_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcRandomAccessFile_IsValid(const PARCRandomAccessFile *instance);
+
+/**
+ * Open a new `PARCRandomAccessFile` instance.
+ *
+ * @param [in] file A `PARCFile` which refers to the file to open for random access.
+ *
+ * @retval `PARCRandomAccessFile` A new instance
+ * @retval NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(file);
+ *
+ * if (parcRandomAccessFile_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+PARCRandomAccessFile *parcRandomAccessFile_Open(PARCFile *file);
+
+/**
+ * Release a previously acquired reference to the given `PARCRandomAccessFile` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+void parcRandomAccessFile_Release(PARCRandomAccessFile **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * PARCJSON *json = parcRandomAccessFile_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcRandomAccessFile_ToJSON(const PARCRandomAccessFile *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCRandomAccessFile`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * char *string = parcRandomAccessFile_ToString(a);
+ *
+ * parcRandomAccessFile_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Display
+ */
+char *parcRandomAccessFile_ToString(const PARCRandomAccessFile *instance);
+
+/**
+ * Close a `PARCRandomAccessFile` instance.
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile.`
+ *
+ * @retval true The file was closed successfully.
+ * @retval false An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * // use the handle
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Open
+ */
+bool parcRandomAccessFile_Close(PARCRandomAccessFile *fileHandle);
+
+/**
+ * Read bytes into the provided `PARCBuffer` until the buffer limit is or the source EOF
+ * is reached.
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile` from which to read.
+ * @param [in,out] buffer A `PARCBuffer` into which data is read.
+ *
+ * @return The number of bytes read.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(1024);
+ * size_t numBytes = parcRandomAccessFile_Read(handle, buffer);
+ *
+ * // use the data in `buffer`
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Write
+ */
+size_t parcRandomAccessFile_Read(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer);
+
+/**
+ * Write bytes from the provided `PARCBuffer` to the source file until the limit is reached.
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile` to which data is written.
+ * @param [in,out] buffer A `PARCBuffer` into which data is read.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapCString("important data to go in the file");
+ * size_t numBytes = parcRandomAccessFile_Write(handle, buffer);
+ *
+ * // continue writing to the file if needed
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Read
+ */
+size_t parcRandomAccessFile_Write(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer);
+
+/**
+ * Seek to the position in the file specified as an offset from the position.
+ *
+ * The position can be one of:
+ * PARCRandomAccessFilePosition_Start
+ * PARCRandomAccessFilePosition_End
+ * PARCRandomAccessFilePosition_Current
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile` to which data is written.
+ * @param [in] offset The number of bytes to offset from the provided position.
+ * @param [in] position The base posititon from which the offset is calculated.
+ *
+ * @return The number of bytes seeked.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * size_t fileSize = parcFile_GetFileSize(file);
+ * parcRandomAccessFile_Seek(handle, -1, PARCRandomAccessFilePosition_End);
+ *
+ * // use the last byte of the file
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Read
+ */
+size_t parcRandomAccessFile_Seek(PARCRandomAccessFile *fileHandle, long offset, PARCRandomAccessFilePosition position);
+#endif
diff --git a/libparc/parc/algol/parc_ReadOnlyBuffer.c b/libparc/parc/algol/parc_ReadOnlyBuffer.c
new file mode 100755
index 00000000..25628ae8
--- /dev/null
+++ b/libparc/parc/algol/parc_ReadOnlyBuffer.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_ReadOnlyBuffer.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_readonly_buffer {
+ PARCBuffer *buffer;
+};
+
+static void
+_readOnlyBuffer_Finalize(PARCReadOnlyBuffer **bufferPtr)
+{
+ PARCReadOnlyBuffer *buffer = *bufferPtr;
+
+ parcBuffer_Release(&buffer->buffer);
+}
+
+parcObject_ExtendPARCObject(PARCReadOnlyBuffer, _readOnlyBuffer_Finalize, parcReadOnlyBuffer_Copy,
+ parcReadOnlyBuffer_ToString, parcReadOnlyBuffer_Equals, NULL, parcReadOnlyBuffer_HashCode, NULL);
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Create(PARCBuffer *buffer)
+{
+ PARCReadOnlyBuffer *result = NULL;
+ if (buffer != NULL) {
+ result = parcObject_CreateInstance(PARCReadOnlyBuffer);
+ if (result != NULL) {
+ result->buffer = parcBuffer_WrapByteArray(parcBuffer_Array(buffer), parcBuffer_Position(buffer), parcBuffer_Limit(buffer));
+ }
+ }
+ return result;
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Wrap(uint8_t *array, size_t arrayLength, size_t position, size_t limit)
+{
+ PARCReadOnlyBuffer *result = parcObject_CreateInstance(PARCReadOnlyBuffer);
+ if (result != NULL) {
+ result->buffer = parcBuffer_Wrap(array, arrayLength, position, limit);
+ }
+ return result;
+}
+
+parcObject_ImplementAcquire(parcReadOnlyBuffer, PARCReadOnlyBuffer);
+
+parcObject_ImplementRelease(parcReadOnlyBuffer, PARCReadOnlyBuffer);
+
+size_t
+parcReadOnlyBuffer_Capacity(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Capacity(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Clear(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Clear(buffer->buffer);
+ return buffer;
+}
+
+bool
+parcReadOnlyBuffer_Equals(const PARCReadOnlyBuffer *x, const PARCReadOnlyBuffer *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ return parcBuffer_Equals(x->buffer, y->buffer);
+}
+
+PARCByteArray *
+parcReadOnlyBuffer_Array(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Array(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Copy(const PARCReadOnlyBuffer *original)
+{
+ PARCReadOnlyBuffer *result = parcObject_CreateInstance(PARCReadOnlyBuffer);
+
+ if (result != NULL) {
+ result->buffer = parcBuffer_Copy(original->buffer);
+ }
+ return result;
+}
+
+size_t
+parcReadOnlyBuffer_ArrayOffset(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_ArrayOffset(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Rewind(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Rewind(buffer->buffer);
+ return buffer;
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Reset(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Reset(buffer->buffer);
+ return buffer;
+}
+
+size_t
+parcReadOnlyBuffer_Limit(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Limit(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Mark(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Mark(buffer->buffer);
+ return buffer;
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_SetLimit(PARCReadOnlyBuffer *buffer, size_t newLimit)
+{
+ parcBuffer_SetLimit(buffer->buffer, newLimit);
+
+ return buffer;
+}
+
+void *
+parcReadOnlyBuffer_Overlay(PARCReadOnlyBuffer *buffer, size_t length)
+{
+ return parcBuffer_Overlay(buffer->buffer, length);
+}
+
+size_t
+parcReadOnlyBuffer_Position(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Position(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_SetPosition(PARCReadOnlyBuffer *buffer, size_t newPosition)
+{
+ parcBuffer_SetPosition(buffer->buffer, newPosition);
+ return buffer;
+}
+
+size_t
+parcReadOnlyBuffer_Remaining(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Remaining(buffer->buffer);
+}
+
+bool
+parcReadOnlyBuffer_HasRemaining(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_HasRemaining(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Flip(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Flip(buffer->buffer);
+ return buffer;
+}
+
+uint8_t
+parcReadOnlyBuffer_GetAtIndex(const PARCReadOnlyBuffer *buffer, size_t index)
+{
+ return parcBuffer_GetAtIndex(buffer->buffer, index);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_GetArray(PARCReadOnlyBuffer *buffer, uint8_t *array, size_t length)
+{
+ parcBuffer_GetBytes(buffer->buffer, length, array);
+ return buffer;
+}
+
+uint8_t
+parcReadOnlyBuffer_GetUint8(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint8(buffer->buffer);
+}
+
+uint16_t
+parcReadOnlyBuffer_GetUint16(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint16(buffer->buffer);
+}
+
+uint32_t
+parcReadOnlyBuffer_GetUint32(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint32(buffer->buffer);
+}
+
+uint64_t
+parcReadOnlyBuffer_GetUint64(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint64(buffer->buffer);
+}
+
+PARCHashCode
+parcReadOnlyBuffer_HashCode(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_HashCode(buffer->buffer);
+}
+
+char *
+parcReadOnlyBuffer_ToString(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_ToString(buffer->buffer);
+}
+
+void
+parcReadOnlyBuffer_Display(const PARCReadOnlyBuffer *buffer, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCReadOnlyBuffer@%p {\n", (void *) buffer);
+ parcBuffer_Display(buffer->buffer, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+}
diff --git a/libparc/parc/algol/parc_ReadOnlyBuffer.h b/libparc/parc/algol/parc_ReadOnlyBuffer.h
new file mode 100644
index 00000000..39dd6aa8
--- /dev/null
+++ b/libparc/parc/algol/parc_ReadOnlyBuffer.h
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_ReadOnlyBuffer.h
+ * @ingroup memory
+ * @brief An indexable, linear buffer of read-only bytes.
+ *
+ * A `PARCReadOnlyBuffer` is a {@link PARCBuffer} that cannot be modified,
+ * but retains a position, limit and capacity.
+ *
+ */
+#ifndef libparc_parc_ReadOnlyBuffer_h
+#define libparc_parc_ReadOnlyBuffer_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_ByteArray.h>
+
+struct parc_readonly_buffer;
+typedef struct parc_readonly_buffer PARCReadOnlyBuffer;
+
+/**
+ * Create a new instance of `PARCBuPARCReadOnlyBuffer` referencing the content of the given {@link PARCBuffer}.
+ *
+ * A reference to the content of the given `PARCBuffer` is acquired.
+ *
+ * The new buffer's position, limit, capacity and mark will be the same as the given `PARCBuffer`.
+ *
+ * If capacity is zero, the buffer contains no underlying byte array.
+ *
+ * @param [in] buffer A pointed to a valid `PARCBuffer` instance.
+ *
+ * @return A `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Create(PARCBuffer *buffer);
+
+/**
+ * Create a new instance of `PARCReadOnlyBuffer` using program supplied memory.
+ *
+ * The new buffer will be backed by the given byte array.
+ * Modifications to the array will be visible through the buffer.
+ *
+ * The new buffer's capacity will be @p arrayLength,
+ * its position will be @p position,
+ * its limit will be @p limit,
+ * and its mark will be undefined.
+ *
+ * Its backing array will be the given array,
+ * and its array offset will be zero.
+ *
+ * @param [in] array A pointer to a memory array.
+ * @param [in] arrayLength The length, in `uint8_t` units, of the memory array.
+ * @param [in] position The initial value for the buffer's position.
+ * @param [in] limit The initial value for the buffer's limit.
+ *
+ * @return A `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Wrap(uint8_t *array, size_t arrayLength, size_t position, size_t limit);
+
+/**
+ * Increase the number of references to a `PARCReadOnlyBuffer`.
+ *
+ * Note that new `PARCReadOnlyBuffer` is not created,
+ * only that the given `PARCReadOnlyBuffer` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` instance.
+ *
+ * @return The input `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * PARCReadOnlyBuffer *handle = parcReadOnlyBuffer_Acquire(roBuffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&handle);
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Acquire(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Release a `PARCReadOnlyBuffer` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCReadOnlyBuffer`.
+ *
+ * @param [in,out] bufferPtr Pointer to the `PARCReadOnlyBuffer` instance to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcReadOnlyBuffer_Release(PARCReadOnlyBuffer **bufferPtr);
+
+/**
+ * Returns this buffer's capacity.
+ *
+ * @param [in] buffer A pointer to a `PARCReadOnlyBuffer` instance.
+ *
+ * @return The given buffer's capacity.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * size_t capacity = parcReadOnlyBuffer_Capacity(roBuffer);
+ * // capacity will be 10
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Capacity(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Clear the given buffer: The position is set to zero,
+ * the limit is set to the capacity,
+ * and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcReadOnlyBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to the `PARCReadOnlyBuffer` instance to be modified.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_Clear(buffer);
+ * }
+ * @endcode
+ *
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Clear(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Determine if two `PARCReadOnlyBuffer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCReadOnlyBuffer` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcReadOnlyBuffer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcReadOnlyBuffer_Equals(x, y)` must return true if and only if
+ * `parcReadOnlyBuffer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcReadOnlyBuffer_Equals(x, y)` returns true and
+ * `parcReadOnlyBuffer_Equals(y, z)` returns true,
+ * then `parcReadOnlyBuffer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcReadOnlyBuffer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcReadOnlyBuffer_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCReadOnlyBuffer` instance.
+ * @param [in] y A pointer to a `PARCReadOnlyBuffer` instance.
+ *
+ * @return true `PARCReadOnlyBuffer` x and y are equal.
+ * @return false `PARCReadOnlyBuffer` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer1 = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ * PARCReadOnlyBuffer *roBuffer2 = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * if (parcReadOnlyBuffer_Equals(roBuffer1, roBuffer2)) {
+ * printf("ROBuffers are equal\n");
+ * } else {
+ * printf("ROBuffers are NOT equal\n");
+ * }
+ *
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+bool parcReadOnlyBuffer_Equals(const PARCReadOnlyBuffer *x, const PARCReadOnlyBuffer *y);
+
+/**
+ * Return a pointer to the {@link PARCByteArray} that backs this buffer.
+ *
+ * If this `PARCReadOnlyBuffer` has a capacity of zero,
+ * there is no array of bytes and this function returns NULL.
+ *
+ * Modifications to the `PARCByteArray` will cause the returned array's content to be modified, and vice versa.
+ *
+ * The caller must obtain its own reference to the `PARCByteArray` if it intends to store it elsewhere.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The pointer to the `PARCByteArray` for the given `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * PARCByteArray *byteArray = parcReadOnlyBuffer_Array(roBuffer);
+ *
+ * ...
+ *
+ * parcByteArray_Release(&byteArray);
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcReadOnlyBuffer_Array(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Create a copy of the given `PARCReadOnlyBuffer`.
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A `PARCReadOnlyBuffer` instance.
+ *
+ * @return A `PARCReadOnlyBuffer` instance which is an identical, independent copy of the original.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * PARCReadOnlyBuffer *copy = parcReadOnlyBuffer_Copy(roBuffer);
+ *
+ * if (parcReadOnlyBuffer_Equals(roBuffer, copy)) {
+ * printf("ROBuffers are equal\n");
+ * }
+ *
+ * parcReadOnlyBuffer_Release(&copy);
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ *
+ * @see parcReadOnlyBuffer_Equals
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Copy(const PARCReadOnlyBuffer *original);
+
+/**
+ * Returns the offset within this buffer's backing {@link PARCByteArray} of the first element.
+ *
+ * Buffer position <i>p</i> corresponds to array index <i>p + arrayOffset()</i>.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The offset within this `PARCReadOnlyBuffer`'s array of the first element of the buffer
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * size_t arrayOffset = parcReadOnlyBuffer_ArrayOffset(buffer);
+ * // offset will be 0 since the contents of the buffer start at the beginning
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_ArrayOffset(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Rewinds this `PARCReadOnlyBuffer`: The position is set to zero and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * {@link PARCBuffer} that requires the mark will abort until the mark
+ * is set again via {@link parcBuffer_Mark}.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Rewind(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Rewind(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Resets the given `PARCReadOnlyBuffer`'s position to the previously-marked position.
+ *
+ * Invoking this method neither changes nor invalidates the mark's value.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Reset(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Reset(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Return the given `PARCReadOnlyBuffer`'s limit.
+ *
+ * A buffer's limit is the index of the first element that should not be read or written.
+ * A buffer's limit is never negative and is never greater than its capacity.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer`'s limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * size_t limit = parcReadOnlyBuffer_Limit(roBuffer);
+ * // limit will be 10
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Limit(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Sets this buffer's mark at its position.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Mark(roBuffer);
+ * // since the position was 0, the mark remains at 0
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Mark(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Sets this `PARCReadOnlyBuffer`'s limit.
+ *
+ * If the position is larger than the new limit then it is set to the new limit.
+ *
+ * If the mark is defined and larger than the new limit then the mark is invalidated and
+ * any subsequent operation that requires the mark will abort until the mark
+ * is set again via {@link parcReadOnlyBuffer_Mark()}.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] newLimit The new limit value; must be no larger than this `PARCReadOnlyBuffer`'s capacity
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_SetLimit(roBuffer, 8);
+ * // the limit is now 8, but the capacity is 10
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_SetLimit(PARCReadOnlyBuffer *buffer, size_t newLimit);
+
+/**
+ * Return a pointer to memory that can be cast to a specific type.
+ *
+ * This does not guarantee proper memory alignment.
+ * It is possible to obtain a pointer to memory that cannot be accessed
+ * as integer or other types because of CPU memory alignment requirements.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] length The number of bytes to advance the buffer's position.
+ *
+ * @return non-NULL A pointer to memory.
+ *
+ * Example:
+ * @code
+ * {
+ * char *expected = "Hello World";
+ * struct timeval theTime = { .tv_sec = 123, .tv_usec = 456};
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t) + strlen(expected) + sizeof(theTime));
+ *
+ * parcBuffer_PutUint16(buffer, strlen(expected));
+ * parcBuffer_PutUint8(buffer, expected, strlen(expected));
+ * parcBuffer_PutUint8(buffer, &theTime, sizeof(theTime));
+ * parcBuffer_Flip();
+ *
+ * uint16_t length = parcBuffer_GetUint16(buffer);
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * char *actual = parcReadOnlyBuffer_Overlay(roBuffer, length);
+ *
+ * struct timeval *tm = parcReadOnlyBuffer_Overlay(roBuffer, sizeof(struct timeval));
+ * }
+ * @endcode
+ */
+void *parcReadOnlyBuffer_Overlay(PARCReadOnlyBuffer *buffer, size_t length);
+
+/**
+ * Return the given `PARCReadOnlyBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * size_t position = parcReadOnlyBuffer_Position(roBuffer);
+ * // position is zero since the position of the underlying buffer is also 0
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Position(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Set the given `PARCReadOnlyBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * If the mark is defined and larger than the new position then the mark
+ * is invalidated and any subsequent operation on the resulting
+ * `PARCReadOnlyBuffer` that requires the mark will abort until the mark
+ * is set again via `parcReadOnlyBuffer_Mark`.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] newPosition The value of the new position which must be less than or equal to the buffer's current limit.
+ *
+ * @return The given `PARCReadOnlyBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Create(parcBuffer_Allocate(10));
+ * parcReadOnlyBuffer_SetPosition(buffer, 5);
+ * parcReadOnlyBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_SetPosition(PARCReadOnlyBuffer *buffer, size_t newPosition);
+
+/**
+ * Returns the number of elements between the current position and the limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The number of elements remaining in this `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_SetPosition(buffer, 5);
+ * parcReadOnlyBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Remaining(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Tells whether there are any elements between the current position and the limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return true if, and only if, there is at least one element remaining in this `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_SetPosition(buffer, 5);
+ * bool remaining = parcReadOnlyBuffer_HasRemaining(buffer);
+ * // remaining is true, since #remaining = 5
+ * }
+ * @endcode
+ */
+bool parcReadOnlyBuffer_HasRemaining(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Set the limit to the current position, then set the position to zero.
+ * If the mark is defined, it is invalidated.
+ *
+ * @param [in,out] buffer The `PARCReadOnlyBuffer` pointer to be modified.
+ *
+ * @return The same value as `buffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ * uint8_t actual = parcReadOnlyBuffer_GetUint8(roBuffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Flip(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Get the single uint8_t at the index specified.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] index The index from which to retrieve the single byte in the buffer.
+ *
+ * @return The uint8_t value at the specified index
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * uint8_t byte = parcReadOnlyBuffer_GetAtIndex(roBuffer, 0);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ */
+uint8_t parcReadOnlyBuffer_GetAtIndex(const PARCReadOnlyBuffer *buffer, size_t index);
+
+/**
+ * Read an array of length bytes from the given PARCReadOnlyBuffer, copying them to an array.
+ *
+ * The buffer's position is incremented by @p length.
+ *
+ * @param [in] buffer The `PARCReadOnlyBuffer` containing the `uint8_t` value.
+ * @param [out] array The `uint8_t` array to receive @p length bytes.
+ * @param [in] length The number of `uint8_t` elements to get..
+ *
+ * @return The given `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ * parcBuffer_PutUint8(buffer, 'A');
+ * parcBuffer_PutUint8(buffer, 'B');
+ * parcBuffer_PutUint8(buffer, 'C');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * uint8_t array[3];
+ * parcReadOnlyBuffer_GetArray(roBuffer, 3, array);
+ * // array[0] == 'A'
+ * // array[1] == 'B'
+ * // array[2] == 'C'
+ * }
+ * @endcode
+ *
+ * @see parcReadOnlyBuffer_Overlay
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_GetArray(PARCReadOnlyBuffer *buffer, uint8_t *array, size_t length);
+
+/**
+ * Get the single `uint8_t` at the current buffer position.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The `uint8_t` value at the current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ *
+ * uint8_t actual = parcReadOnlyBuffer_GetUint8(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint8_t parcReadOnlyBuffer_GetUint8(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Get the single `uint16_t` at the current buffer position.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The `uint16_t` value at the current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint16(buffer, 0x1234);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ *
+ * uint16_t actual = parcReadOnlyBuffer_GetUint16(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint16_t parcReadOnlyBuffer_GetUint16(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Get the single `uint32_t` at the current buffer position.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The `uint32_t` value at the current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint32(buffer, 0x12345678);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ *
+ * uint32_t actual = parcReadOnlyBuffer_GetUint32(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint32_t parcReadOnlyBuffer_GetUint32(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Read the unsigned 64-bit value in network order at the buffer's current position,
+ * and then increment the position by 8.
+ *
+ * @param [in,out] buffer The `PARCReadOnlyBuffer` containing the value.
+ *
+ * @return The `uint64_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint64_t));
+ * parcBuffer_PutUint64(buffer, 0x1234567812345678);
+ * parcBuffer_Flip(buffer);
+ *
+ * PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ * uint64_t actual = parcReadOnlyBuffer_GetUint64(&readOnly);
+ * }
+ * @endcode
+ */
+uint64_t parcReadOnlyBuffer_GetUint64(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the {@link parcReadOnlyBuffer_HashCode} function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcReadOnlyBuffer_Equals()}
+ * comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcReadOnlyBuffer_Equals} method,
+ * then calling the {@link parcReadOnlyBuffer_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the {@link parcReadOnlyBuffer_Equals()} function,
+ * then calling the {@link parcReadOnlyBuffer_HashCode()}
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] buffer A pointer to the `PARCReadOnlyBuffer` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * uint32_t hashValue = parcReadOnlyBuffer_HashCode(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcReadOnlyBuffer_Equals
+ */
+PARCHashCode parcReadOnlyBuffer_HashCode(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Create a null-terminated C string containing the bytes of the given `PARCReadOnlyBuffer`.
+ *
+ * The string consists of the bytes from the current position of the buffer to its limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to a null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = parcReadOnlyBuffer_ToString(buffer);
+ *
+ * parcMemory_Deallocate((void **)&string);
+ * }
+ * @endcode
+ */
+char *parcReadOnlyBuffer_ToString(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Print a human readable representation of the given `PARCReadOnlyBuffer`.
+ *
+ * Print on standard output a human readable representation of the given `PARCReadOnlyBuffer` indented by the level indicated.
+ *
+ * @param [in] buffer A pointer to the `PARCReadOnlyBuffer` instance.
+ * @param [in] indentation The number of tabs by which to indent the output strings.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_Display(buffer, 0);
+ * }
+ * @endcode
+ */
+void parcReadOnlyBuffer_Display(const PARCReadOnlyBuffer *buffer, int indentation);
+#endif // libparc_parc_ReadOnlyBuffer_h
diff --git a/libparc/parc/algol/parc_SafeMemory.c b/libparc/parc/algol/parc_SafeMemory.c
new file mode 100644
index 00000000..1f152af9
--- /dev/null
+++ b/libparc/parc/algol/parc_SafeMemory.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is a substitute for posix_memalign(3) that
+ * establishes detectable boundaries around an allocated memory segment,
+ * records a stack backtrace for each allocation,
+ * detects buffer overruns and underruns by checking the boundaries when the memory is deallocated,
+ * and tries to prevent a stray pointer to reference the memory again once it's been deallocated.
+ *
+ * The allocated memory consists of three contiguous segments: the prefix, the memory usable by the caller, and the suffix.
+ * The memory usable by the caller is aligned as specified by the caller.
+ * The alignment must be a power of 2 greater than or equal to the size of a {@code void *}.
+ * <pre>
+ * +--base +-prefix +-- memory +-- suffix aligned on (void *)
+ * v v v v
+ * |________|PPPPPPPPPPPP|mmmmmmmmm...mmmm|___|SSSSSSSSS
+ * ^
+ * +-- variable padding
+ * </pre>
+ * Where '-' indicates padding, 'P' indicates the prefix data structure, 'm'
+ * indicates contiguous memory for use by the caller, and 'S" indicates the suffix data structure.
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#if defined(_WIN64)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(_WIN32)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__ANDROID__)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__APPLE__)
+# include <execinfo.h>
+#elif defined(__linux)
+# include <execinfo.h>
+#elif defined(__unix) // all unices not caught above
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__posix)
+# include <execinfo.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+#include <pthread.h>
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_StdlibMemory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+typedef struct memory_backtrace {
+ void **callstack;
+ int maximumFrameCount;
+ int actualFrameCount;
+} _MemoryBacktrace;
+
+static const uint32_t _parcSafeMemory_SuffixGuard = 0xcafecafe;
+typedef struct memory_suffix {
+ uint32_t guard;
+} _MemorySuffix;
+
+static const uint64_t _parcSafeMemory_PrefixMagic = 0xfacefacefaceface;
+static const uint64_t _parcSafeMemory_Guard = 0xdeaddeaddeaddead;
+static const uint64_t _parcSafeMemory_GuardAlreadyFreed = 0xBADDCAFEBADDCAFE;
+typedef struct memory_prefix {
+ uint64_t magic; // A magic number indicating the start of this data structure.
+ size_t requestedLength; // The number of bytes the caller requested.
+ size_t actualLength; // The number of bytes >= requestedLength to ensure the right alignment for the suffix.
+ size_t alignment; // The aligment required by the caller. Must be a power of 2 and >= sizeof(void *).
+ _MemoryBacktrace *backtrace; // A record of the caller's stack trace at the time of allocation.
+ uint64_t guard; // Try to detect underrun of the allocated memory.
+} _MemoryPrefix;
+
+typedef void *PARCSafeMemoryOrigin;
+
+typedef void *PARCSafeMemoryUsable;
+
+static PARCMemoryInterface *_parcMemory = &PARCStdlibMemoryAsPARCMemory;
+
+static pthread_mutex_t _parcSafeMemory_Mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+/**
+ * Return true if the given alignment value is greater than or equal to {@code sizeof(void *)} and
+ * is a power of 2.
+ *
+ * @param alignment
+ * @return
+ */
+static bool
+_alignmentIsValid(size_t alignment)
+{
+ return alignment >= sizeof(void *) && (alignment & (~alignment + 1)) == alignment;
+}
+
+/**
+ * Add two pointers arithmetically.
+ */
+// Should increment be a ssize_t, instead of size_t?
+static void *
+_pointerAdd(const void *base, const size_t increment)
+{
+ void *result = (void *) &((char *) base)[increment];
+ return result;
+}
+
+static size_t
+_computePrefixLength(const size_t alignment)
+{
+ return (sizeof(_MemoryPrefix) + alignment - 1) & ~(alignment - 1);
+}
+
+static size_t
+_computeUsableMemoryLength(const size_t requestedLength, const size_t alignment)
+{
+ return (requestedLength + alignment - 1) & ~(alignment - 1);
+}
+
+/**
+ * Compute the size of the suffix on an allocated chunk of managed memory that causes the
+ * first byte after this size to be aligned according to the given alignment value.
+ */
+static size_t
+_computeSuffixLength(size_t alignment __attribute__((unused)))
+{
+ return sizeof(_MemorySuffix);
+}
+
+/**
+ * Compute the total number of bytes necessary to store the entire Safe Memory structure.
+ * Given a size number of bytes for use by a client function,
+ * produce the total number of bytes necessary to store @p size
+ * number of bytes for use by a client function and the `_MemoryPrefix`
+ * and `_MemorySuffix` structures.
+ */
+static size_t
+_computeMemoryTotalLength(size_t requestedLength, size_t alignment)
+{
+ size_t result =
+ _computePrefixLength(alignment)
+ + _computeUsableMemoryLength(requestedLength, sizeof(void*))
+ + _computeSuffixLength(alignment);
+
+ return result;
+}
+
+/**
+ * Given the safe memory address, return a pointer to the _MemoryPrefix structure.
+ */
+static _MemoryPrefix *
+_parcSafeMemory_GetPrefix(const PARCSafeMemoryUsable *usable)
+{
+ _MemoryPrefix *prefix = _pointerAdd(usable, -sizeof(_MemoryPrefix));
+ return prefix;
+}
+
+/**
+ * Given a base address for memory Return a pointer to the {@link _MemorySuffix}
+ * structure for the given base pointer to allocated memory.
+ *
+ * @param base
+ * @return
+ */
+static _MemorySuffix *
+_parcSafeMemory_GetSuffix(const PARCSafeMemoryUsable *memory)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ _MemorySuffix *suffix = _pointerAdd(memory, prefix->actualLength);
+ return suffix;
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_GetPrefixState(const PARCSafeMemoryUsable *usable)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(usable);
+
+ if (prefix->guard == _parcSafeMemory_GuardAlreadyFreed) {
+ return PARCSafeMemoryState_ALREADYFREE;
+ }
+ if (prefix->guard != _parcSafeMemory_Guard) {
+ return PARCSafeMemoryState_UNDERRUN;
+ }
+ if (prefix->magic != _parcSafeMemory_PrefixMagic) {
+ return PARCSafeMemoryState_UNDERRUN;
+ }
+ if (!_alignmentIsValid(prefix->alignment)) {
+ return PARCSafeMemoryState_UNDERRUN;
+ }
+
+ return PARCSafeMemoryState_OK;
+}
+
+static PARCSafeMemoryOrigin *
+_parcSafeMemory_GetOrigin(const PARCSafeMemoryUsable *memory)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ return _pointerAdd(memory, -_computePrefixLength(prefix->alignment));
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_GetSuffixState(const PARCSafeMemoryUsable *memory)
+{
+ PARCSafeMemoryState result = PARCSafeMemoryState_OK;;
+ _MemorySuffix *suffix = _parcSafeMemory_GetSuffix(memory);
+ if (suffix->guard != _parcSafeMemory_SuffixGuard) {
+ result = PARCSafeMemoryState_OVERRUN;
+ }
+ return result;
+}
+
+/**
+ * Given a pointer to the base address of an allocated memory segment,
+ * compute and return a pointer to the corresponding {@link _MemorySuffix} for that same memory.
+ */
+static _MemorySuffix *
+_parcSafeMemory_FormatSuffix(const PARCSafeMemoryUsable *memory)
+{
+ _MemorySuffix *suffix = _parcSafeMemory_GetSuffix(memory);
+
+ suffix->guard = _parcSafeMemory_SuffixGuard;
+ return suffix;
+}
+
+static void
+_backtraceReport(const _MemoryBacktrace *backtrace, int outputFd)
+{
+ if (outputFd != -1) {
+ // Ignore the first entry as it points to this function and we just need to start at the calling function.
+ backtrace_symbols_fd(&backtrace->callstack[1], backtrace->actualFrameCount - 1, outputFd);
+ }
+}
+
+// This is a list of all memory allocations that were created by calls to Safe Memory.
+// Each element of the list is the pointer to the result returned to the caller of the memory allocation,
+// not a pointer to the base.
+struct safememory_entry {
+ LIST_ENTRY(safememory_entry) entries; // List
+ void *memory;
+};
+LIST_HEAD(, safememory_entry) head = LIST_HEAD_INITIALIZER(head);
+static pthread_mutex_t head_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+_parcSafeMemory_AddAllocation(void *memory)
+{
+ if (parcSafeMemory_Outstanding() == 0) {
+ LIST_INIT(&head); // Initialize the list.
+ }
+
+ struct safememory_entry *e = malloc(sizeof(struct safememory_entry)); // Insert this at the head.
+ e->memory = memory;
+
+ pthread_mutex_lock(&head_mutex);
+ LIST_INSERT_HEAD(&head, e, entries);
+ pthread_mutex_unlock(&head_mutex);
+}
+
+static void
+_parcSafeMemory_RemoveAllocation(void *memory)
+{
+ struct safememory_entry *e;
+ pthread_mutex_lock(&head_mutex);
+ LIST_FOREACH(e, &head, entries)
+ {
+ if (e->memory == memory) {
+ LIST_REMOVE(e, entries);
+ free(e);
+ pthread_mutex_unlock(&head_mutex);
+ return;
+ }
+ }
+
+ pthread_mutex_unlock(&head_mutex);
+ fprintf(stderr, "parcSafeMemory_RemoveAllocation: Destroying memory (%p) which is NOT in the allocated memory record. Double free?\n", memory);
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_GetState(const PARCSafeMemoryUsable *memory)
+{
+ PARCSafeMemoryState prefixState = _parcSafeMemory_GetPrefixState(memory);
+ if (prefixState != PARCSafeMemoryState_OK) {
+ return prefixState;
+ }
+ return _parcSafeMemory_GetSuffixState(memory);
+}
+
+static const char *
+_parcSafeMemory_StateToString(PARCSafeMemoryState status)
+{
+ switch (status) {
+ case PARCSafeMemoryState_OK: return "OK";
+ case PARCSafeMemoryState_MISMATCHED: return "MISMATCHED";
+ case PARCSafeMemoryState_UNDERRUN: return "UNDERRUN";
+ case PARCSafeMemoryState_OVERRUN: return "OVERRUN";
+ case PARCSafeMemoryState_NOTHINGALLOCATED: return "NOTHINGALLOCATED";
+ case PARCSafeMemoryState_ALREADYFREE: return "ALREADYFREE";
+ }
+ return "?";
+}
+
+static void
+_parcSafeMemory_Report(const PARCSafeMemoryUsable *safeMemory, int outputFd)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(safeMemory);
+
+ if (outputFd != -1) {
+ int charactersPrinted = dprintf(outputFd, "Memory %p (base %p) %s\n",
+ (void *) safeMemory,
+ (void *) prefix,
+ _parcSafeMemory_StateToString(_parcSafeMemory_GetState(safeMemory)));
+ trapUnexpectedStateIf(charactersPrinted < 0, "Cannot write to file descriptor %d", outputFd);
+ }
+ _backtraceReport(prefix->backtrace, outputFd);
+}
+
+uint32_t
+parcSafeMemory_ReportAllocation(int outputFd)
+{
+ uint32_t index = 0;
+ struct safememory_entry *e;
+
+ pthread_mutex_lock(&head_mutex);
+ LIST_FOREACH(e, &head, entries)
+ {
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(e->memory);
+ if (outputFd != -1) {
+ int charactersPrinted = dprintf(outputFd,
+ "\n%u SafeMemory@%p: %p={ .requestedLength=%zd, .actualLength=%zd, .alignment=%zd }\n",
+ index, e->memory, (void *) prefix, prefix->requestedLength, prefix->actualLength, prefix->alignment);
+ trapUnexpectedStateIf(charactersPrinted < 0, "Cannot write to file descriptor %d", outputFd)
+ {
+ pthread_mutex_unlock(&head_mutex);
+ }
+ }
+ _parcSafeMemory_Report(e->memory, outputFd);
+ index++;
+ }
+ pthread_mutex_unlock(&head_mutex);
+ return parcSafeMemory_Outstanding();
+}
+
+static void
+_backtraceDestroy(_MemoryBacktrace **backtrace)
+{
+ free((*backtrace)->callstack);
+ free(*backtrace);
+ *backtrace = 0;
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_Destroy(void **memoryPointer)
+{
+ pthread_mutex_lock(&_parcSafeMemory_Mutex);
+
+ if (parcSafeMemory_Outstanding() == 0) {
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ return PARCSafeMemoryState_NOTHINGALLOCATED;
+ }
+
+ _parcSafeMemory_RemoveAllocation(*memoryPointer);
+
+ PARCSafeMemoryUsable *memory = *memoryPointer;
+
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ trapUnexpectedStateIf(state != PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemoryState_OK, actual %s (see parc_SafeMemory.h)",
+ _parcSafeMemory_StateToString(state))
+ {
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ }
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+ _backtraceDestroy(&prefix->backtrace);
+
+ PARCSafeMemoryOrigin *base = _parcSafeMemory_GetOrigin(memory);
+
+ memset(base, 0, _computeMemoryTotalLength(prefix->requestedLength, prefix->alignment));
+ prefix->guard = _parcSafeMemory_GuardAlreadyFreed;
+
+ ((PARCMemoryDeallocate *) _parcMemory->Deallocate)((void **) &base);
+
+ *memoryPointer = 0;
+
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ return PARCSafeMemoryState_OK;
+}
+
+__attribute__((unused))
+static void
+_parcSafeMemory_DeallocateAll(void)
+{
+ struct safememory_entry *e;
+
+ pthread_mutex_lock(&head_mutex);
+ LIST_FOREACH(e, &head, entries)
+ {
+ _parcSafeMemory_Destroy(&e->memory);
+ }
+ pthread_mutex_unlock(&head_mutex);
+}
+
+static _MemoryBacktrace *
+_backtraceCreate(int maximumFrameCount)
+{
+ _MemoryBacktrace *result = malloc(sizeof(_MemoryBacktrace));
+ result->maximumFrameCount = maximumFrameCount;
+ result->callstack = calloc(result->maximumFrameCount, sizeof(void *));
+
+ result->actualFrameCount = backtrace(result->callstack, result->maximumFrameCount);
+
+ return result;
+}
+
+/**
+ * Format memory with a MemoryPrefix structure.
+ *
+ * @param origin The origin of the allocated memory (which is not the same as the start of usable memory).
+ * @param requestedLength The length of the extent of memory for general purpose use by the caller.
+ * @param alignment A power of 2 greater than or equal to {@code sizeof(void *)}.
+ * @return The pointer to the first address suitable for general purpose use by the caller.
+ */
+static PARCSafeMemoryUsable *
+_parcSafeMemory_FormatPrefix(PARCSafeMemoryOrigin *origin, size_t requestedLength, size_t alignment)
+{
+ int backTraceDepth = 20;
+
+ if (!_alignmentIsValid(alignment)) {
+ return NULL;
+ }
+ size_t prefixSize = _computePrefixLength(alignment);
+
+ // This abuts the prefix to the user memory, it does not start at the beginning
+ // of the aligned prefix region.
+ _MemoryPrefix *prefix = (_MemoryPrefix *) (origin + (prefixSize - sizeof(_MemoryPrefix)));
+
+ prefix->magic = _parcSafeMemory_PrefixMagic;
+ prefix->requestedLength = requestedLength;
+ prefix->actualLength = _computeUsableMemoryLength(requestedLength, sizeof(void*));
+ prefix->alignment = alignment;
+ prefix->backtrace = _backtraceCreate(backTraceDepth);
+ prefix->guard = _parcSafeMemory_Guard;
+
+ PARCSafeMemoryUsable *result = _pointerAdd(origin, prefixSize);
+
+ assertAligned(result, alignment, "Return value is not properly aligned to %zu", alignment);
+ return result;
+}
+
+/**
+ * Given a pointer to allocated memory and the length of bytes that will be used by the caller,
+ * format the prefix and suffix structures returning a pointer to the first properly aligned
+ * byte available to the client function.
+ */
+static void *
+_parcSafeMemory_FormatMemory(PARCSafeMemoryOrigin *origin, size_t length, size_t alignment)
+{
+ PARCSafeMemoryUsable *memory = _parcSafeMemory_FormatPrefix(origin, length, alignment);
+ if (memory != NULL) {
+ _parcSafeMemory_FormatSuffix(memory);
+ }
+
+ return memory;
+}
+
+int
+parcSafeMemory_MemAlign(void **memptr, size_t alignment, size_t requestedSize)
+{
+ if (!_alignmentIsValid(alignment)) {
+ return EINVAL;
+ }
+ if (requestedSize == 0) {
+ return EINVAL;
+ }
+
+ size_t totalSize = _computeMemoryTotalLength(requestedSize, alignment);
+ if (totalSize < requestedSize) {
+ return ERANGE;
+ }
+
+ pthread_mutex_lock(&_parcSafeMemory_Mutex);
+
+ void *base;
+ int failure = ((PARCMemoryMemAlign *) _parcMemory->MemAlign)(&base, alignment, totalSize);
+
+ if (failure != 0 || base == NULL) {
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ return ENOMEM;
+ }
+
+ *memptr = _parcSafeMemory_FormatMemory(base, requestedSize, alignment);
+
+ _parcSafeMemory_AddAllocation(*memptr);
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+
+ return 0;
+}
+
+void *
+parcSafeMemory_Allocate(size_t requestedSize)
+{
+ void *result = NULL;
+
+ if (requestedSize != 0) {
+ size_t totalSize = _computeMemoryTotalLength(requestedSize, sizeof(void *));
+
+ if (totalSize >= requestedSize) {
+ pthread_mutex_lock(&_parcSafeMemory_Mutex);
+
+ void *base = ((PARCMemoryAllocate *) _parcMemory->Allocate)(totalSize);
+ if (base != NULL) {
+ result = _parcSafeMemory_FormatMemory(base, requestedSize, sizeof(void *));
+
+ _parcSafeMemory_AddAllocation(result);
+ }
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ }
+ }
+ return result;
+}
+
+void *
+parcSafeMemory_AllocateAndClear(size_t requestedSize)
+{
+ void *memptr = parcSafeMemory_Allocate(requestedSize);
+ if (memptr != NULL) {
+ memset(memptr, 0, requestedSize);
+ }
+ return memptr;
+}
+
+bool
+parcSafeMemory_IsValid(const void *memory)
+{
+ bool result = true;
+
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ if (state != PARCSafeMemoryState_OK) {
+ return false;
+ }
+
+ return result;
+}
+
+
+uint32_t
+parcSafeMemory_Outstanding(void)
+{
+ return ((PARCMemoryOutstanding *) _parcMemory->Outstanding)();
+}
+
+void *
+parcSafeMemory_Reallocate(void *original, size_t newSize)
+{
+ void *result;
+
+ result = parcSafeMemory_Allocate(newSize);
+
+ if (original == NULL) {
+ return result;
+ }
+
+ if (result != NULL) {
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(original);
+ size_t originalSize = prefix->requestedLength;
+
+ memcpy(result, original, originalSize);
+ parcSafeMemory_Deallocate(&original);
+ }
+ return result;
+}
+
+char *
+parcSafeMemory_StringDuplicate(const char *string, size_t length)
+{
+ size_t actualLength = strlen(string);
+ if (length < actualLength) {
+ actualLength = length;
+ }
+
+ char *result = parcSafeMemory_Allocate(actualLength + 1);
+ if (result != NULL) {
+ memcpy(result, string, actualLength);
+ result[actualLength] = 0;
+ }
+ return result;
+}
+
+void
+parcSafeMemory_Deallocate(void **pointer)
+{
+ _parcSafeMemory_Destroy(pointer);
+}
+
+void
+parcSafeMemory_Display(const void *memory, int indentation)
+{
+ if (memory == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCSafeMemory@NULL");
+ } else {
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ parcDisplayIndented_PrintLine(indentation, "PARCSafeMemory@%p {", (void *) memory);
+ parcDisplayIndented_PrintLine(indentation + 1,
+ "%p=[ magic=0x%" PRIx64 " requestedLength=%zd, actualLength=%zd, alignment=%zd, guard=0x%" PRIx64 "]",
+ _parcSafeMemory_GetOrigin(memory),
+ prefix->magic,
+ prefix->requestedLength,
+ prefix->actualLength,
+ prefix->alignment,
+ prefix->guard);
+
+ parcDisplayIndented_PrintMemory(indentation + 1, prefix->requestedLength, memory);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+ }
+}
+
+PARCMemoryInterface PARCSafeMemoryAsPARCMemory = {
+ .Allocate = (uintptr_t) parcSafeMemory_Allocate,
+ .AllocateAndClear = (uintptr_t) parcSafeMemory_AllocateAndClear,
+ .MemAlign = (uintptr_t) parcSafeMemory_MemAlign,
+ .Deallocate = (uintptr_t) parcSafeMemory_Deallocate,
+ .Reallocate = (uintptr_t) parcSafeMemory_Reallocate,
+ .Outstanding = (uintptr_t) parcSafeMemory_Outstanding,
+ .StringDuplicate = (uintptr_t) parcSafeMemory_StringDuplicate
+};
diff --git a/libparc/parc/algol/parc_SafeMemory.h b/libparc/parc/algol/parc_SafeMemory.h
new file mode 100644
index 00000000..0383fe39
--- /dev/null
+++ b/libparc/parc/algol/parc_SafeMemory.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_SafeMemory.h
+ * @ingroup developer
+ *
+ * @brief Facade to memory functions to make calls safer.
+ *
+ * This is a facade to interpose between an application and the standard C library functions posix_memalign(3),
+ * malloc(3), calloc(3), realloc(3) and free(3) that establishes detectable boundaries around an allocated memory segment,
+ * records a stack backtrace for each allocation,
+ * detects buffer overruns and underruns by checking the boundaries when the memory is deallocated,
+ * and tries to prevent a stray pointer to reference the memory again once it's been deallocated.
+ *
+ * The allocated memory consists of three contiguous segments: the prefix, the memory usable by the caller, and the suffix.
+ * The memory usable by the caller is aligned as specified by the caller.
+ * The alignment must be a power of 2 greater than or equal to the size of a {@code void *}.
+ * <pre>
+ * +--base +-prefix +-- aligned memory +-- suffix aligned on (void *)
+ * v v v v
+ * |________|PPPPPPPPPPPP|mmmmmmmmm...mmmm|___|SSSSSSSSS
+ * ^
+ * +-- variable padding
+ * </pre>
+ * Where '-' indicates padding, 'P' indicates the prefix data structure, 'm'
+ * indicates contiguous memory for use by the caller, and 'S" indicates the suffix data structure.
+ *
+ * To enable this facade, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_SafeMemory_h
+#define libparc_parc_SafeMemory_h
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Memory.h>
+
+typedef enum parc_safety_memory_state {
+ PARCSafeMemoryState_OK = 0,
+ PARCSafeMemoryState_MISMATCHED = 1,
+ PARCSafeMemoryState_UNDERRUN = 2,
+ PARCSafeMemoryState_OVERRUN = 3,
+ PARCSafeMemoryState_NOTHINGALLOCATED = 4,
+ PARCSafeMemoryState_ALREADYFREE = 5
+} PARCSafeMemoryState;
+
+/**
+ * Generate a readable, null-terminated C string representation
+ * for the specified `PARCSafeMemoryState` type.
+ *
+ * @param [in] status A `PARCSafeMemoryState` value.
+ *
+ * @return A null-terminated C string that must be freed when done.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * uint32_t alignment = sizeof(void *);
+ * void *memory;
+ *
+ * memory = parcSafeMemory_Allocate(size);
+ * PARCSafeMemoryState state = parcSafeMemory_Destroy(&memory);
+ *
+ * printf("SafeMemoryState = %s\n", parcSafeMemoryState_ToString(state));
+ * }
+ * @endcode
+ */
+const char *parcSafeMemoryState_ToString(PARCSafeMemoryState status);
+
+/**
+ * Memory operations defined by {@link PARCMemoryInterface}
+ * and implemented by the Safe Memory functions.
+ */
+extern PARCMemoryInterface PARCSafeMemoryAsPARCMemory;
+
+/**
+ * Allocate Safe Memory.
+ *
+ * Allocate memory through the configured memory allocator, setting the environment to track this memory.
+ *
+ * @param [in] size The number of bytes necessary.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * void *memory = parcSafeMemory_Allocate(size);
+ * }
+ * @endcode
+ */
+void *parcSafeMemory_Allocate(size_t size);
+
+/**
+ * Allocate Safe Memory.
+ *
+ * Allocate memory through the configured memory allocator, setting the environment to track this memory.
+ *
+ * @param [in] requestedSize The number of bytes necessary.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * void *memory = parcSafeMemory_Allocate(size);
+ * }
+ * @endcode
+ */
+void *parcSafeMemory_AllocateAndClear(size_t requestedSize);
+
+/**
+ * Allocate aligned memory.
+ *
+ * Allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * int failure = parcSafeMemory_MemAlign(&allocatedMemory, sizeof(void *), 100);
+ * if (failure == 0) {
+ * parcSafeMemory_Deallocate(&allocatedMemory);
+ * // allocatedMemory is now equal to zero.
+ * }
+ * }
+ * @endcode
+ * @see `posix_memalign`
+ */
+int parcSafeMemory_MemAlign(void **pointer, size_t alignment, size_t size);
+
+/**
+ * Deallocate memory previously allocated with {@link parcSafeMemory_Allocate}
+ *
+ * The value pointed to by @p pointer will be set to NULL.
+ *
+ * @param [in,out] pointer A pointer to a pointer to the allocated memory.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * void *memory = parcSafeMemory_Allocate(size);
+ *
+ * parcSafeMemory_Deallocate(&memory);
+ * }
+ * @endcode
+ */
+void parcSafeMemory_Deallocate(void **pointer);
+
+/**
+ * A (mostly) suitable replacement for realloc(3).
+ * The primary difference is that it is an error if newSize is zero.
+ * If the newSize is equal to the old size, then NULL is returned.
+ *
+ * @param [in] original Pointer to the original memory
+ * @param [in] newSize The size of the newly re-allocated memory.
+ *
+ * @return Non-NULL A pointer to the newly allocated memory
+ * @return NULL An error occurred (newSize == oldSize, or newSize == 0)
+ *
+ * Example:
+ * @code
+ * {
+ * void *memory = parcSafeMemory_Allocate(100);
+ *
+ * size_t newLength = 0;
+ * unsigned char *newMemory = parcSafeMemory_Reallocate(memory, newLength);
+ *
+ * assertTrue(newMemory == NULL, "Expected NULL, actual %p", newMemory);
+ * }
+ * @endcode
+ */
+void *parcSafeMemory_Reallocate(void *original, size_t newSize);
+
+/**
+ * Duplicate the given null-terminated C string.
+ *
+ * @param [in] string A pointer to a null-terminated C string.
+ * @param [in] length The length of the string, not including the terminating null character.
+ *
+ * @return non-NULL Allocated Safe Memory containing the duplicate string. This must be freed via `parcSafeMemory_Deallocate`.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = "hello world";
+ * char *actual = parcSafeMemory_StringDuplicate(string, strlen(string));
+ * ...
+ * }
+ * @endcode
+ *
+ * @see parcSafeMemory_Deallocate
+ */
+char *parcSafeMemory_StringDuplicate(const char *string, size_t length);
+
+/**
+ * Return the number of outstanding allocations.
+ *
+ * In practice, every allocation should be matched with a corresponding deallocation.
+ * This return the number of allocations that have not been deallocated.
+ *
+ * @return The number of outstanding allocations.
+ *
+ */
+uint32_t parcSafeMemory_Outstanding(void);
+
+/**
+ * Display information about outstanding memory allocations.
+ *
+ * To enable this function, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @param [in] outputFd Output file descriptor.
+ *
+ * @return The number of currenly outstanding allocations.
+ *
+ * Example:
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ *
+ * ...
+ *
+ * FILE *fd = fopen ("log.txt", "w");
+ * size_t outstandingAllocations = parcSafeMemory_ReportAllocation(fd);
+ * }
+ * @endcode
+ */
+uint32_t parcSafeMemory_ReportAllocation(int outputFd);
+
+/**
+ * Determine if a pointer to Safe Memory is valid.
+ *
+ * Invalid indicates the memory is overrun or underrun.
+ *
+ * To enable this function, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @param [in] memory A pointer to previously allocated Safe Memory.
+ *
+ * @return true The memory is valid;
+ * @return false The memory is invalid;
+ *
+ * Example:
+ * @code
+ * {
+ * void *memory = parcSafeMemory_Allocate(100);
+ * if (parcSafeMemory_IsValid(memory) == false) {
+ * printf("Memory is invalid\n");
+ * }
+ * @endcode
+ */
+bool parcSafeMemory_IsValid(const void *memory);
+
+/**
+ * Print a human readable representation of the given PARC Safe Memory array.
+ *
+ * To enable this function, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] memory A pointer to the memory to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *instance = parcBuffer_Create();
+ *
+ * parcBuffer_Display(instance, 0);
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcSafeMemory_Display(const void *memory, int indentation);
+#endif // libparc_parc_SafeMemory_h
diff --git a/libparc/parc/algol/parc_SortedList.c b/libparc/parc/algol/parc_SortedList.c
new file mode 100644
index 00000000..8a941701
--- /dev/null
+++ b/libparc/parc/algol/parc_SortedList.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_SortedList.h>
+#include <parc/algol/parc_LinkedList.h>
+
+struct PARCSortedList {
+ PARCLinkedList *list;
+ PARCSortedListEntryCompareFunction compare;
+};
+
+static void
+_parcSortedList_Finalize(PARCSortedList **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSortedList pointer.");
+ PARCSortedList *instance = *instancePtr;
+
+ parcSortedList_OptionalAssertValid(instance);
+
+ parcLinkedList_Release(&instance->list);
+}
+
+parcObject_ImplementAcquire(parcSortedList, PARCSortedList);
+
+parcObject_ImplementRelease(parcSortedList, PARCSortedList);
+
+parcObject_ExtendPARCObject(PARCSortedList, _parcSortedList_Finalize, parcSortedList_Copy, parcSortedList_ToString, parcSortedList_Equals, NULL, parcSortedList_HashCode, parcSortedList_ToJSON);
+
+
+void
+parcSortedList_AssertValid(const PARCSortedList *instance)
+{
+ assertTrue(parcSortedList_IsValid(instance),
+ "PARCSortedList is not valid.");
+}
+
+
+PARCSortedList *
+parcSortedList_Create(void)
+{
+ PARCSortedList *result = parcSortedList_CreateCompare(parcObject_Compare);
+
+ return result;
+}
+
+PARCSortedList *
+parcSortedList_CreateCompare(PARCSortedListEntryCompareFunction compare)
+{
+ PARCSortedList *result = parcObject_CreateInstance(PARCSortedList);
+
+ if (result != NULL) {
+ result->list = parcLinkedList_Create();
+ result->compare = compare;
+ }
+
+ return result;
+}
+
+PARCSortedList *
+parcSortedList_Copy(const PARCSortedList *original)
+{
+ PARCSortedList *result = parcObject_CreateInstance(PARCSortedList);
+
+ if (result != NULL) {
+ result->list = parcLinkedList_Copy(original->list);
+ }
+
+ return result;
+}
+
+void
+parcSortedList_Display(const PARCSortedList *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCSortedList@%p {", instance);
+ parcLinkedList_Display(instance->list, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcSortedList_Equals(const PARCSortedList *x, const PARCSortedList *y)
+{
+ return parcLinkedList_Equals(x->list, y->list);
+}
+
+PARCHashCode
+parcSortedList_HashCode(const PARCSortedList *instance)
+{
+ PARCHashCode result = parcLinkedList_HashCode(instance->list);
+
+ return result;
+}
+
+bool
+parcSortedList_IsValid(const PARCSortedList *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcSortedList_ToJSON(const PARCSortedList *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcSortedList_ToString(const PARCSortedList *instance)
+{
+ char *result = parcMemory_Format("PARCSortedList@%p\n", instance);
+
+ return result;
+}
+
+size_t
+parcSortedList_Size(const PARCSortedList *list)
+{
+ return parcLinkedList_Size(list->list);
+}
+
+PARCObject *
+parcSortedList_GetAtIndex(const PARCSortedList *list, const size_t index)
+{
+ return parcLinkedList_GetAtIndex(list->list, index);
+}
+
+PARCObject *
+parcSortedList_GetFirst(const PARCSortedList *list)
+{
+ return parcLinkedList_GetAtIndex(list->list, 0);
+}
+
+PARCObject *
+parcSortedList_GetLast(const PARCSortedList *list)
+{
+ return parcLinkedList_GetAtIndex(list->list, parcLinkedList_Size(list->list) - 1);
+}
+
+PARCObject *
+parcSortedList_RemoveFirst(PARCSortedList *list)
+{
+ PARCObject *result = parcLinkedList_RemoveFirst(list->list);
+
+ return result;
+}
+
+PARCObject *
+parcSortedList_RemoveLast(PARCSortedList *list)
+{
+ PARCObject *result = parcLinkedList_RemoveLast(list->list);
+
+ return result;
+}
+
+bool
+parcSortedList_Remove(PARCSortedList *list, const PARCObject *object)
+{
+ bool result = false;
+
+ PARCIterator *iterator = parcSortedList_CreateIterator(list);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *o = parcIterator_Next(iterator);
+ if (parcObject_Equals(object, o)) {
+ parcIterator_Remove(iterator);
+ result = true;
+ break;
+ }
+ }
+
+ parcIterator_Release(&iterator);
+
+ return result;
+}
+
+static size_t
+_parcSortedList_GetInsertionIndex(const PARCSortedList *instance, const PARCObject *element)
+{
+ ssize_t low = 0;
+ ssize_t high = parcLinkedList_Size(instance->list) - 1;
+
+ if (high == -1) {
+ return 0;
+ }
+
+ while (true) {
+ ssize_t midpoint = (low + (high - low) / 2);
+ PARCObject *e = parcLinkedList_GetAtIndex(instance->list, midpoint);
+ int signum = instance->compare(element, e);
+ if (high == low) {
+ if (signum < 0) {
+ return high;
+ } else if (signum > 0) {
+ return low + 1;
+ } else {
+ return low;
+ }
+ }
+
+ if (signum < 0) {
+ high = midpoint;
+ } else if (signum > 0) {
+ low = midpoint + 1;
+ } else {
+ return midpoint;
+ }
+ }
+
+ return -1;
+}
+
+PARCIterator *
+parcSortedList_CreateIterator(PARCSortedList *instance)
+{
+ return parcLinkedList_CreateIterator(instance->list);
+}
+
+void
+parcSortedList_Add(PARCSortedList *instance, PARCObject *element)
+{
+ size_t insertionPoint = _parcSortedList_GetInsertionIndex(instance, element);
+ assertTrue(insertionPoint >= 0 && insertionPoint <= parcLinkedList_Size(instance->list),
+ "%zd is bad insertion point. Must be >=0 and <= %zd", insertionPoint, parcLinkedList_Size(instance->list));
+
+ parcLinkedList_InsertAtIndex(instance->list, insertionPoint, element);
+}
diff --git a/libparc/parc/algol/parc_SortedList.h b/libparc/parc/algol/parc_SortedList.h
new file mode 100644
index 00000000..393992e7
--- /dev/null
+++ b/libparc/parc/algol/parc_SortedList.h
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_SortedList.h
+ * @ingroup datastructures
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_SortedList
+#define PARCLibrary_parc_SortedList
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct PARCSortedList;
+typedef struct PARCSortedList PARCSortedList;
+
+typedef int (*PARCSortedListEntryCompareFunction)(const PARCObject *objA, const PARCObject *objB);
+
+/**
+ * Increase the number of references to a `PARCSortedList` instance.
+ *
+ * Note that new `PARCSortedList` is not created,
+ * only that the given `PARCSortedList` reference count is incremented.
+ * Discard the reference by invoking `parcSortedList_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCSortedList *b = parcSortedList_Acquire();
+ *
+ * parcSortedList_Release(&a);
+ * parcSortedList_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Acquire(const PARCSortedList *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcSortedList_OptionalAssertValid(_instance_)
+#else
+# define parcSortedList_OptionalAssertValid(_instance_) parcSortedList_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCSortedList` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcSortedList_Release(&b);
+ * }
+ * @endcode
+ */
+void parcSortedList_AssertValid(const PARCSortedList *instance);
+
+/**
+ * Create an instance of PARCSortedList
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCSortedList instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Create(void);
+
+/**
+ * Create an instance of PARCSortedList and provide a comparison function.
+ *
+ * @param [in] compare A pointer to a function that implements the Compare contract.
+ *
+ * @return non-NULL A pointer to a valid PARCSortedList instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_CreateCompare(PARCSortedListEntryCompareFunction compare);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCSortedList instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCSortedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCSortedList *copy = parcSortedList_Copy(&b);
+ *
+ * parcSortedList_Release(&b);
+ * parcSortedList_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Copy(const PARCSortedList *original);
+
+/**
+ * Print a human readable representation of the given `PARCSortedList`.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Display(a, 0);
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSortedList_Display(const PARCSortedList *instance, int indentation);
+
+/**
+ * Determine if two `PARCSortedList` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCSortedList` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcSortedList_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcSortedList_Equals(x, y)` must return true if and only if
+ * `parcSortedList_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcSortedList_Equals(x, y)` returns true and
+ * `parcSortedList_Equals(y, z)` returns true,
+ * then `parcSortedList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcSortedList_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcSortedList_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCSortedList instance.
+ * @param [in] y A pointer to a valid PARCSortedList instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ * PARCSortedList *b = parcSortedList_Create();
+ *
+ * if (parcSortedList_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcSortedList_Release(&a);
+ * parcSortedList_Release(&b);
+ * }
+ * @endcode
+ * @see parcSortedList_HashCode
+ */
+bool parcSortedList_Equals(const PARCSortedList *x, const PARCSortedList *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcSortedList_Equals} method,
+ * then calling the {@link parcSortedList_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcSortedList_Equals} function,
+ * then calling the `parcSortedList_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCHashCode hashValue = parcSortedList_HashCode(buffer);
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcSortedList_HashCode(const PARCSortedList *instance);
+
+/**
+ * Determine if an instance of `PARCSortedList` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * if (parcSortedList_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcSortedList_IsValid(const PARCSortedList *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSortedList` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSortedList_Release(PARCSortedList **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCJSON *json = parcSortedList_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcSortedList_ToJSON(const PARCSortedList *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCSortedList`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * char *string = parcSortedList_ToString(a);
+ *
+ * parcSortedList_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcSortedList_Display
+ */
+char *parcSortedList_ToString(const PARCSortedList *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcSortedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCSortedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcSortedList_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcSortedList, PARCSortedList);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcSortedList_Wait`, `parcSortedList_WaitFor`, `parcSortedList_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcSortedList_Lock(object)) {
+ * parcSortedList_NotifyAll(object);
+ * parcSortedList_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcSortedList, PARCSortedList);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcSortedList_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcSortedList_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcSortedList, PARCSortedList);
+
+parcObject_ImplementWaitFor(parcSortedList, PARCSortedList);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the `parcSortedList_Notify()`
+ * function on the same object or the system time equals or exceeds the specified time.
+ *
+ * The calling thread must own the object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes
+ * `parcSortedList_Notify` or the computer's system time equals or exceeds that specified by @p time.
+ * on the same object.
+ * The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCSortedList instance.
+ *
+ * @returns false if the alloted time was exceeded.
+ * @returns true if another thread invoked the `parcSortedList_Notify()` or `parcSortedList_NotifyAll()` function
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval tv;
+ * gettimeofday(&tv, NULL);
+ *
+ * struct timespec absoluteTime;
+ * absoluteTime.tv_sec = tv.tv_sec + 0;
+ * absoluteTime.tv_nsec = 0;
+ *
+ * parcSortedList_WaitUntil(object, &absoluteTime);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWaitUntil(parcSortedList, PARCSortedList);
+
+/**
+ * Obtain the lock on the given `PARCSortedList` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCSortedList` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcSortedList_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcSortedList, PARCSortedList);
+
+/**
+ * Try to obtain the advisory lock on the given PARCSortedList instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCSortedList instance.
+ *
+ * @return true The PARCSortedList is locked.
+ * @return false The PARCSortedList is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSortedList_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcSortedList, PARCSortedList);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCSortedList` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * @return true The `PARCSortedList` was locked and now is unlocked.
+ * @return false The `PARCSortedList` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSortedList_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcSortedList, PARCSortedList);
+
+/**
+ * Determine if the advisory lock on the given `PARCSortedList` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * @return true The `PARCSortedList` is locked.
+ * @return false The `PARCSortedList` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcSortedList_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcSortedList, PARCSortedList);
+
+PARCIterator *parcSortedList_CreateIterator(PARCSortedList *instance);
+
+void parcSortedList_Add(PARCSortedList *instance, PARCObject *element);
+
+size_t parcSortedList_Size(const PARCSortedList *list);
+
+PARCObject *parcSortedList_GetAtIndex(const PARCSortedList *list, const size_t index);
+
+/**
+ * Return the first element of the specified list.
+ * The element's reference count is not modified,
+ * the caller must acquire its own reference to the element if it is needed beyond lifetime of the given list.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the first element will be returned.
+ *
+ * @return non NULL A pointer to the element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_GetFirst(const PARCSortedList *list);
+
+/**
+ * Return the last element of the specified list.
+ * The element's reference count is not modified,
+ * the caller must acquire its own reference to the element if it is needed beyond lifetime of the given list.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the last element will be returned.
+ *
+ * @return non NULL A pointer to the element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_GetLast(const PARCSortedList *list);
+
+
+bool parcSortedList_Remove(PARCSortedList *list, const PARCObject *object);
+/**
+ * Return the first element of the specified list and remove it from the list.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the first element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_RemoveFirst(PARCSortedList *list);
+
+/**
+ * Return the last element of the specified list and remove it from the list.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the last element will be removed and returned.
+ *
+ * @return non-NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_RemoveLast(PARCSortedList *list);
+
+#endif
diff --git a/libparc/parc/algol/parc_Stack.c b/libparc/parc/algol/parc_Stack.c
new file mode 100755
index 00000000..5930169b
--- /dev/null
+++ b/libparc/parc/algol/parc_Stack.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_Stack.h>
+
+struct parc_stack {
+ void *instance;
+ PARCStackInterface *interface;
+};
+
+PARCStack *
+parcStack(void *instance, PARCStackInterface *interface)
+{
+ PARCStack *result = parcMemory_AllocateAndClear(sizeof(PARCStack));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCStack));
+ result->instance = instance;
+ result->interface = interface;
+
+ return result;
+}
+
+void
+parcStack_Release(PARCStack **stackPtr)
+{
+ PARCStack *stack = *stackPtr;
+ (stack->interface->parcStack_Release)(&stack->instance);
+ parcMemory_Deallocate((void **) &stack);
+
+ *stackPtr = 0;
+}
+
+bool
+parcStack_IsEmpty(const PARCStack *stack)
+{
+ return (stack->interface->parcStack_IsEmpty)(stack->instance);
+}
+
+void *
+parcStack_Peek(const PARCStack *stack)
+{
+ return (stack->interface->parcStack_Peek)(stack->instance);
+}
+
+void *
+parcStack_Pop(PARCStack *stack)
+{
+ return (stack->interface->parcStack_Pop)(stack->instance);
+}
+
+void *
+parcStack_Push(PARCStack *stack, void *element)
+{
+ return (stack->interface->parcStack_Push)(stack->instance, element);
+}
diff --git a/libparc/parc/algol/parc_Stack.h b/libparc/parc/algol/parc_Stack.h
new file mode 100755
index 00000000..e64e02f4
--- /dev/null
+++ b/libparc/parc/algol/parc_Stack.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Stack.h
+ * @ingroup datastructures
+ * @brief PARC (Generic) Stack
+ *
+ * A stack interface implementation.
+ *
+ * Example
+ * @code
+ * #include <parc/algol/parc_Deque.h>
+ *
+ * int
+ * main(int argc, char *argv[])
+ * {
+ * PARCStackInterface dequeAsStack = {
+ * .parcStack_Release = parcDeque_Release,
+ * .parcStack_IsEmpty = parcDeque_IsEmpty,
+ * .parcStack_Peek = parcDeque_PeekLast,
+ * .parcStack_Pop = parcDeque_RemoveLast,
+ * .parcStack_Push = parcDeque_Append,
+ * .parcStack_Search = NULL
+ * };
+ *
+ * PARCStack *stack = parcStack(parcDeque_Create(), &dequeAsStack);
+ *
+ * parcStack_IsEmpty(stack);
+ * }
+ * @endcode
+ *
+ *
+ */
+#ifndef libparc_parc_Stack_h
+#define libparc_parc_Stack_h
+
+#include <stdbool.h>
+
+struct parc_stack;
+typedef struct parc_stack PARCStack;
+
+typedef struct parc_stack_interface {
+ /**
+ * Release the instance
+ *
+ *
+ * @param [in,out] instancePtr A pointer to the pointer of the instance to release.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void (*parcStack_Release)(void **instancePtr);
+
+ /**
+ * Tests if this stack is empty.
+ *
+ * @param [in] instance A pointer to the instance to test.
+ * @return true if the stack is empty
+ * @return false if the stack is not empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*parcStack_IsEmpty)(const void *instance);
+
+ /**
+ * Looks at the object at the top of this stack without removing it from the stack.
+ *
+ * @param [in] instance A pointer to the instance to look at.
+ * @return The object at the top of the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void * (*parcStack_Peek)(const void *instance);
+
+ /**
+ * Removes the object at the top of this stack and returns that object as the value of this function.
+ *
+ *
+ * @param [in,out] instance A pointer to the instance to check and modify.
+ * @return The object at the top of the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void * (*parcStack_Pop)(void *instance);
+
+ /**
+ * Pushes an item onto the top of this stack.
+ *
+ *
+ * @param [in,out] instance A pointer to the instance to modify.
+ * @param [in] item A pointer to the object to push on the @p instance.
+ * @return A pointer to the object that was pushed on the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void * (*parcStack_Push)(void *instance, void *item);
+
+ /**
+ * Returns the 1-based position where an object is on this stack.
+ *
+ *
+ * @param [in] instance A pointer to the instance.
+ * @param [in] element A pointer to the element to find on the @p instance.
+ * @return The index of the position where @p element is found in the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ int (*parcStack_Search)(void *instance, void *element);
+} PARCStackInterface;
+#endif // libparc_parc_Stack_h
diff --git a/libparc/parc/algol/parc_StandardOutputStream.c b/libparc/parc/algol/parc_StandardOutputStream.c
new file mode 100644
index 00000000..0c46ce3c
--- /dev/null
+++ b/libparc/parc/algol/parc_StandardOutputStream.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <parc/algol/parc_StandardOutputStream.h>
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_Object.h>
+
+struct PARCStandardOutputStream {
+ int fd;
+};
+
+static struct PARCOutputStreamImplementation _implementation = {
+ .Write = PARCStandardOutputStream_Write,
+ .Acquire = PARCStandardOutputStream_Acquire,
+ .Release = PARCStandardOutputStream_Release;
+};
+
+static void
+_parcStandardOutputStream_Destroy(PARCStandardOutputStream **streamPtr)
+{
+ parcObject_Release((void **) streamPtr);
+}
+
+static const PARCObjectImpl _parcStandardOutputStream_Object = {
+ .destroy = (PARCObjectDestroy *) _parcStandardOutputStream_Destroy,
+ .copy = NULL,
+ .toString = NULL,
+ .equals = NULL,
+ .compare = NULL
+};
+
+PARCOutputStream *
+parcStandardOutputStream(void)
+{
+ PARCStandardOutputStream *instance = PARCStandardOutputStream_Create();
+ parcOutputStream(instance, &_implementation)
+}
+
+PARCStandardOutputStream *
+PARCStandardOutputStream_Create(void)
+{
+ parcObject_Create(sizeof(PARCStandardOutputStream), &_parcStandardOutputStream_Object);
+ return NULL;
+}
+
+PARCStandardOutputStream *
+PARCStandardOutputStream_Acquire(PARCStandardOutputStream *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+void
+PARCStandardOutputStream_Release(PARCStandardOutputStream **instanceP)
+{
+ parcObject_Release((void **) instanceP);
+}
+
+bool
+parcFileOutputStream_Write(PARCStandardOutputStream *stream, PARCBuffer *buffer)
+{
+ return false;
+}
diff --git a/libparc/parc/algol/parc_StandardOutputStream.h b/libparc/parc/algol/parc_StandardOutputStream.h
new file mode 100644
index 00000000..be5a21d3
--- /dev/null
+++ b/libparc/parc/algol/parc_StandardOutputStream.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_StandardOutputStream.h
+ * @brief Standard output stream structures and functions.
+ *
+ */
+
+#ifndef __PARC_Library__parc_StandardOutputStream__
+#define __PARC_Library__parc_StandardOutputStream__
+
+struct PARCStandardOutputStream;
+typedef struct PARCStandardOutputStream PARCStandardOutputStream;
+
+#include <parc/algol/parc_OutputStream.h>
+
+PARCOutputStream *parcStandardOutputStream(void);
+
+PARCStandardOutputStream *PARCStandardOutputStream_Create(void);
+
+PARCStandardOutputStream *PARCStandardOutputStream_Acquire(PARCStandardOutputStream *instance);
+
+void PARCStandardOutputStream_Release(PARCStandardOutputStream **instanceP);
+
+#endif /* defined(__PARC_Library__parc_StandardOutputStream__) */
diff --git a/libparc/parc/algol/parc_StdlibMemory.c b/libparc/parc/algol/parc_StdlibMemory.c
new file mode 100755
index 00000000..a919f727
--- /dev/null
+++ b/libparc/parc/algol/parc_StdlibMemory.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_StdlibMemory.h>
+
+static uint32_t _parcStdlibMemory_OutstandingAllocations;
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+static pthread_mutex_t _parcStdlibMemory_Mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static inline void
+_parcStdlibMemory_IncrementOutstandingAllocations(void)
+{
+ pthread_mutex_lock(&_parcStdlibMemory_Mutex);
+ _parcStdlibMemory_OutstandingAllocations++;
+ pthread_mutex_unlock(&_parcStdlibMemory_Mutex);
+}
+
+static inline void
+_parcStdlibMemory_DecrementOutstandingAllocations(void)
+{
+ pthread_mutex_lock(&_parcStdlibMemory_Mutex);
+ _parcStdlibMemory_OutstandingAllocations--;
+ pthread_mutex_unlock(&_parcStdlibMemory_Mutex);
+}
+#else
+
+static inline void
+_parcStdlibMemory_IncrementOutstandingAllocations(void)
+{
+ __sync_add_and_fetch(&_parcStdlibMemory_OutstandingAllocations, 1);
+}
+
+static inline void
+_parcStdlibMemory_DecrementOutstandingAllocations(void)
+{
+ __sync_sub_and_fetch(&_parcStdlibMemory_OutstandingAllocations, 1);
+}
+#endif
+
+#ifndef HAVE_REALLOC
+static void *
+_parcStdlibMemory_rplRealloc(void *oldAlloc, size_t newSize)
+{
+ if (newSize == 0) {
+ newSize = 1;
+ }
+
+ char *newAlloc = malloc(newSize);
+
+ if (oldAlloc != NULL) {
+ memcpy(newAlloc, oldAlloc, newSize);
+ free(oldAlloc);
+ }
+ return newAlloc;
+}
+#endif
+
+void *
+parcStdlibMemory_Allocate(size_t size)
+{
+ if (size == 0) {
+ return NULL;
+ }
+
+ void *result = malloc(size);
+ if (result != NULL) {
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+ }
+
+ return result;
+}
+
+void *
+parcStdlibMemory_AllocateAndClear(size_t size)
+{
+ void *pointer = parcStdlibMemory_Allocate(size);
+ if (pointer != NULL) {
+ memset(pointer, 0, size);
+ }
+ return pointer;
+}
+
+int
+parcStdlibMemory_MemAlign(void **pointer, size_t alignment, size_t size)
+{
+ if (size == 0) {
+ return EINVAL;
+ }
+
+ int failure = posix_memalign(pointer, alignment, size);
+
+ if (failure != 0) {
+ return failure;
+ }
+ if (*pointer == NULL) {
+ return ENOMEM;
+ }
+
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+
+ return 0;
+}
+
+void
+parcStdlibMemory_Deallocate(void **pointer)
+{
+#ifndef PARCLibrary_DISABLE_VALIDATION
+ trapIllegalValueIf(_parcStdlibMemory_OutstandingAllocations == 0,
+ "parcStdlibMemory_Deallocate invoked with nothing left to free (double free somewhere?)\n");
+#endif
+ free(*pointer);
+ *pointer = NULL;
+
+ _parcStdlibMemory_DecrementOutstandingAllocations();
+}
+
+void *
+parcStdlibMemory_Reallocate(void *pointer, size_t newSize)
+{
+#ifdef HAVE_REALLOC
+ void *result = realloc(pointer, newSize);
+#else
+ void *result = _parcStdlibMemory_rplRealloc(pointer, newSize);
+#endif
+
+ if (pointer == NULL) {
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+ }
+ return result;
+}
+
+char *
+parcStdlibMemory_StringDuplicate(const char *string, size_t length)
+{
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+ return strndup(string, length);
+}
+
+uint32_t
+parcStdlibMemory_Outstanding(void)
+{
+ return _parcStdlibMemory_OutstandingAllocations;
+}
+
+PARCMemoryInterface PARCStdlibMemoryAsPARCMemory = {
+ .Allocate = (uintptr_t) parcStdlibMemory_Allocate,
+ .AllocateAndClear = (uintptr_t) parcStdlibMemory_AllocateAndClear,
+ .MemAlign = (uintptr_t) parcStdlibMemory_MemAlign,
+ .Deallocate = (uintptr_t) parcStdlibMemory_Deallocate,
+ .Reallocate = (uintptr_t) parcStdlibMemory_Reallocate,
+ .StringDuplicate = (uintptr_t) parcStdlibMemory_StringDuplicate,
+ .Outstanding = (uintptr_t) parcStdlibMemory_Outstanding
+};
diff --git a/libparc/parc/algol/parc_StdlibMemory.h b/libparc/parc/algol/parc_StdlibMemory.h
new file mode 100755
index 00000000..9abbf915
--- /dev/null
+++ b/libparc/parc/algol/parc_StdlibMemory.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_StdlibMemory.h
+ * @ingroup datastructures
+ *
+ * @brief Standard library memory mangement functions wrapped up to be suitable for use by parc_Memory.[ch]
+ *
+ */
+#ifndef libparc_parc_StdlibMemory_h
+#define libparc_parc_StdlibMemory_h
+
+#include <parc/algol/parc_Memory.h>
+
+extern PARCMemoryInterface PARCStdlibMemoryAsPARCMemory;
+
+/**
+ * Allocate memory.
+ *
+ * @param [in] size The size of memory to allocate
+ *
+ * @return A pointer to the allocated memory.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcStdlibMemory_Allocate(size_t size);
+
+/**
+ * Allocate memory of size @p size and clear it.
+ *
+ * @param [in] size Size of memory to allocate
+ *
+ * @return A pointer to the allocated memory
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcStdlibMemory_AllocateAndClear(size_t size);
+
+/**
+ * Allocate aligned memory.
+ *
+ * Allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * int failure = parcStdlibMemory_MemAlign(&allocatedMemory, sizeof(void *), 100);
+ * if (failure == 0) {
+ * parcStdlibMemory_Deallocate(&allocatedMemory);
+ * // allocatedMemory is now equal to zero.
+ * }
+ * }
+ * @endcode
+ * @see {@link parcMemory_MemAlign}
+ */
+int parcStdlibMemory_MemAlign(void **pointer, size_t alignment, size_t size);
+
+/**
+ * Deallocate the memory pointed to by @p pointer
+ *
+ * @param [in,out] pointer A pointer to a pointer to the memory to be deallocated
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcStdlibMemory_Deallocate(void **pointer);
+
+/**
+ * Resizes previously allocated memory at @p pointer to @p newSize. If necessary,
+ * new memory is allocated and the content copied from the old memory to the
+ * new memory and the old memory is deallocated.
+ *
+ * @param [in,out] pointer A pointer to the memory to be reallocated.
+ * @param [in] newSize The size that the memory to be resized to.
+ *
+ * @return A pointer to the memory
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcStdlibMemory_Reallocate(void *pointer, size_t newSize);
+
+/**
+ * Allocate sufficient memory for a copy of the string @p string,
+ * copy at most n characters from the string @p string into the allocated memory,
+ * and return the pointer to allocated memory.
+ *
+ * The copied string is always null-terminated.
+ *
+ * @param [in] string A pointer to a null-terminated string.
+ * @param [in] length The maximum allowed length of the resulting copy.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = "this is a string";
+ * char *copy = parcStdlibMemory_StringDuplicate(string, strlen(string));
+ *
+ * if (copy != NULL) {
+ * . . .
+ * parcStdLibMemory_Deallocate(&copy);
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link parcStdlibMemory_Deallocate()}
+ */
+char *parcStdlibMemory_StringDuplicate(const char *string, size_t length);
+
+/**
+ * Return the number of outstanding allocations managed by this allocator.
+ *
+ * When you allocate memory, this count goes up by one. When you deallocate, it goes down by one.
+ * A well-behaved program will terminate with a call to `parcStdlibMemory_Outstanding()` returning 0.
+ *
+ * @return The number of memory allocations still outstanding (remaining to be deallocated).
+ *
+ * Example:
+ * @code
+ * {
+ * uint32_t numberOfAllocations = parcStdlibMemory_Outstanding();
+ * }
+ * @endcode
+ */
+uint32_t parcStdlibMemory_Outstanding(void);
+
+
+/**
+ * Replacement function for realloc(3).
+ *
+ * The standard `realloc()` function tries to change the size of the allocation pointed to by @p oldAlloc to @p newSize,
+ * and returns @p oldAlloc. If there is not enough room to enlarge the memory allocation pointed to by @p oldAlloc,
+ * realloc() creates a new allocation, copies as much of the old data pointed to by @p oldAlloc as will fit to the new allocation,
+ * frees the old allocation, and returns a pointer to the allocated memory.
+ *
+ * If @p oldAlloc is `NULL`, `realloc()` is identical to a call to `malloc()` for size bytes.
+ * If @p newSize is zero and @p oldAlloc is not NULL, a new, minimum sized object is allocated and the original object is freed.
+ * When extending a region allocated with `calloc(3)`, `realloc(3)` does not guarantee that the additional memory
+ * is also zero-filled.
+ *
+ * If the realloc(3) function is not compatible with the above constraints
+ * (i.e., ‘realloc(NULL, 0)’ returns an invalid pointer), then autoconf tools will define
+ * `realloc` to `rpl_realloc` so that the native realloc is not used in the main project.
+ *
+ * @param [in] oldAlloc A previously allocated
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *rpl_realloc(void *oldAlloc, size_t newSize);
+#endif // libparc_parc_StdlibMemory_h
diff --git a/libparc/parc/algol/parc_String.c b/libparc/parc/algol/parc_String.c
new file mode 100755
index 00000000..e5af5f71
--- /dev/null
+++ b/libparc/parc/algol/parc_String.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/algol/parc_String.h>
+
+struct PARCString {
+ char *string;
+};
+
+static bool
+_parcString_Destructor(PARCString **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCString pointer.");
+ PARCString *string = *instancePtr;
+
+ parcMemory_Deallocate(&string->string);
+ return true;
+}
+
+parcObject_ImplementAcquire(parcString, PARCString);
+
+parcObject_ImplementRelease(parcString, PARCString);
+
+parcObject_Override(PARCString, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcString_Destructor,
+ .copy = (PARCObjectCopy *) parcString_Copy,
+ .display = (PARCObjectDisplay *) parcString_Display,
+ .toString = (PARCObjectToString *) parcString_ToString,
+ .equals = (PARCObjectEquals *) parcString_Equals,
+ .compare = (PARCObjectCompare *) parcString_Compare,
+ .hashCode = (PARCObjectHashCode *) parcString_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcString_ToJSON,
+ .display = (PARCObjectDisplay *) parcString_Display);
+
+void
+parcString_AssertValid(const PARCString *instance)
+{
+ assertTrue(parcString_IsValid(instance),
+ "PARCString is not valid.");
+}
+
+PARCString *
+parcString_Create(const char *string)
+{
+ PARCString *result = parcObject_CreateInstance(PARCString);
+ if (result != NULL) {
+ result->string = parcMemory_StringDuplicate(string, strlen(string));
+ }
+ return result;
+}
+
+PARCString *
+parcString_CreateFromBuffer(const PARCBuffer *buffer)
+{
+ PARCString *result = parcString_Create(parcBuffer_Overlay((PARCBuffer *) buffer, 0));
+
+ return result;
+}
+
+int
+parcString_Compare(const PARCString *string, const PARCString *other)
+{
+ int result = 0;
+
+ if (string == NULL) {
+ if (other != NULL) {
+ result = -1;
+ }
+ } else if (other == NULL) {
+ result = 1;
+ } else {
+ parcString_OptionalAssertValid(string);
+ parcString_OptionalAssertValid(other);
+
+ int comparison = strcmp(string->string, other->string);
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+PARCString *
+parcString_Copy(const PARCString *original)
+{
+ PARCString *result = parcString_Create(original->string);
+
+ return result;
+}
+
+void
+parcString_Display(const PARCString *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCString@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "%s", instance->string);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcString_Equals(const PARCString *x, const PARCString *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ parcString_OptionalAssertValid(x);
+ parcString_OptionalAssertValid(y);
+
+ result = strcmp(x->string, y->string) == 0;
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcString_HashCode(const PARCString *string)
+{
+ PARCHashCode result = 0;
+
+ result = parcHashCode_Hash((uint8_t *) string->string, strlen(string->string));
+
+ return result;
+}
+
+bool
+parcString_IsValid(const PARCString *string)
+{
+ bool result = false;
+
+ if (string != NULL) {
+ if (string->string != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcString_ToJSON(const PARCString *string)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcString_ToString(const PARCString *string)
+{
+ char *result = parcMemory_StringDuplicate(string->string, strlen(string->string));
+
+ return result;
+}
+
+const char *
+parcString_GetString(const PARCString *string)
+{
+ parcString_OptionalAssertValid(string);
+
+ return string->string;
+}
diff --git a/libparc/parc/algol/parc_String.h b/libparc/parc/algol/parc_String.h
new file mode 100644
index 00000000..4fe4307f
--- /dev/null
+++ b/libparc/parc/algol/parc_String.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_String.h
+ * @ingroup types
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_String
+#define PARCLibrary_parc_String
+#include <stdbool.h>
+#include <string.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+typedef struct PARCString PARCString;
+extern parcObjectDescriptor_Declaration(PARCString);
+
+/**
+ * Increase the number of references to a `PARCString` instance.
+ *
+ * Note that new `PARCString` is not created,
+ * only that the given `PARCString` reference count is incremented.
+ * Discard the reference by invoking `parcString_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCString *b = parcString_Acquire();
+ *
+ * parcString_Release(&a);
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ */
+PARCString *parcString_Acquire(const PARCString *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcString_OptionalAssertValid(_instance_)
+#else
+# define parcString_OptionalAssertValid(_instance_) parcString_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCString` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ */
+void parcString_AssertValid(const PARCString *instance);
+
+/**
+ * Create an instance of PARCString
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCString instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCString *parcString_Create(const char *);
+
+/**
+ * Create an instance of PARCString from the content of a given PARCBuffer.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCString instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCString *parcString_CreateFromBuffer(const PARCBuffer *buffer);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ * @param [in] other A pointer to a valid PARCString instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ * PARCString *b = parcString_Create();
+ *
+ * if (parcString_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcString_Release(&a);
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcString_Equals
+ */
+int parcString_Compare(const PARCString *instance, const PARCString *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCString instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCString` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCString *copy = parcString_Copy(&b);
+ *
+ * parcString_Release(&b);
+ * parcString_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCString *parcString_Copy(const PARCString *original);
+
+/**
+ * Print a human readable representation of the given `PARCString`.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Display(a, 0);
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+void parcString_Display(const PARCString *instance, int indentation);
+
+/**
+ * Determine if two `PARCString` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCString` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcString_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcString_Equals(x, y)` must return true if and only if
+ * `parcString_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcString_Equals(x, y)` returns true and
+ * `parcString_Equals(y, z)` returns true,
+ * then `parcString_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcString_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcString_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCString instance.
+ * @param [in] y A pointer to a valid PARCString instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ * PARCString *b = parcString_Create();
+ *
+ * if (parcString_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcString_Release(&a);
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ * @see parcString_HashCode
+ */
+bool parcString_Equals(const PARCString *x, const PARCString *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcString_Equals} method,
+ * then calling the {@link parcString_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcString_Equals} function,
+ * then calling the `parcString_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCHashCode hashValue = parcString_HashCode(buffer);
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcString_HashCode(const PARCString *instance);
+
+/**
+ * Determine if an instance of `PARCString` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * if (parcString_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcString_IsValid(const PARCString *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCString` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+void parcString_Release(PARCString **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCJSON *json = parcString_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcString_ToJSON(const PARCString *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCString`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * char *string = parcString_ToString(a);
+ *
+ * parcString_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcString_Display
+ */
+char *parcString_ToString(const PARCString *instance);
+
+/**
+ * Get a pointer to the underlying nul-terminated sequence of bytes containing the string's value.
+ *
+ * @param [in] string A pointer to a valid PARCString instance.
+ *
+ * @return A pointer to the underlying nul-terminated sequence of bytes
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcString_GetString(const PARCString *string);
+#endif
diff --git a/libparc/parc/algol/parc_Time.c b/libparc/parc/algol/parc_Time.c
new file mode 100755
index 00000000..7cc358b9
--- /dev/null
+++ b/libparc/parc/algol/parc_Time.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_Memory.h>
+
+char *
+parcTime_TimevalAsString(struct timeval timeval)
+{
+ char *string;
+ int nwritten = asprintf(&string, "%ld.%06ld", timeval.tv_sec, (long) timeval.tv_usec);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+char *
+parcTime_TimevalAsRFC3339(const struct timeval *utcTime, char result[64])
+{
+ char tmbuf[64];
+ struct tm theTime;
+
+ struct tm *nowtm = gmtime_r(&utcTime->tv_sec, &theTime);
+ strftime(tmbuf, sizeof tmbuf, "%Y-%m-%dT%H:%M:%S", nowtm);
+ snprintf(result, 64, "%s.%06ldZ", tmbuf, (long) utcTime->tv_usec);
+ return result;
+}
+
+char *
+parcTime_TimevalAsISO8601(const struct timeval *utcTime, char result[64])
+{
+ char tmbuf[64];
+ struct tm theTime;
+
+ struct tm *nowtm = gmtime_r(&utcTime->tv_sec, &theTime);
+ strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
+ snprintf(result, 64, "%s.%06ldZ", tmbuf, (long) utcTime->tv_usec);
+ return result;
+}
+
+char *
+parcTime_TimeAsRFC3339(const time_t utcTime, char result[64])
+{
+ struct timeval theTime = { utcTime, 0 };
+
+ return parcTime_TimevalAsRFC3339(&theTime, result);
+}
+
+char *
+parcTime_NowAsRFC3339(char result[64])
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ return parcTime_TimevalAsRFC3339(&theTime, result);
+}
+
+char *
+parcTime_TimeAsISO8601(const time_t utcTime, char result[64])
+{
+ struct timeval theTime = { utcTime, 0 };
+
+ return parcTime_TimevalAsISO8601(&theTime, result);
+}
+
+char *
+parcTime_NowAsISO8601(char result[64])
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ return parcTime_TimevalAsISO8601(&theTime, result);
+}
+
+struct timeval
+parcTime_TimevalAdd(const struct timeval *addend1, const struct timeval *addend2)
+{
+ struct timeval sum;
+
+ sum.tv_sec = addend1->tv_sec + addend2->tv_sec;
+ sum.tv_usec = addend1->tv_usec + addend2->tv_usec;
+ if (sum.tv_usec >= 1000000) {
+ sum.tv_usec -= 1000000;
+ sum.tv_sec++;
+ }
+ return sum;
+}
+
+struct timeval
+parcTime_TimevalSubtract(const struct timeval *minuend, const struct timeval *subtrahend)
+{
+ struct timeval result;
+
+ result.tv_sec = minuend->tv_sec - subtrahend->tv_sec;
+ result.tv_usec = minuend->tv_usec - subtrahend->tv_usec;
+ if (result.tv_usec < 0) {
+ result.tv_sec--;
+ result.tv_usec += 1000000;
+ }
+ return result;
+}
+
+struct timeval
+parcTime_NowTimeval(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+ return timeval;
+}
+
+uint64_t
+parcTime_NowMicroseconds(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ uint64_t result = timeval.tv_sec * 1000000 + timeval.tv_usec;
+ return result;
+}
+
+uint64_t
+parcTime_NowNanoseconds(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ uint64_t result = timeval.tv_sec * 1000000000 + timeval.tv_usec * 1000;
+ return result;
+}
diff --git a/libparc/parc/algol/parc_Time.h b/libparc/parc/algol/parc_Time.h
new file mode 100644
index 00000000..2a68144e
--- /dev/null
+++ b/libparc/parc/algol/parc_Time.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Time.h
+ * @ingroup inputoutput
+ * @brief Time Manipulation
+ *
+ * Different platforms have different ways to express time-of-day, elapsed-time, clock-time.
+ * In some cases multiple ways to express the same semantic value have evolved over time,
+ * for example `struct timeval` and `struct timespec`.
+ *
+ */
+#ifndef libparc_parc_Time_h
+#define libparc_parc_Time_h
+
+#include <sys/time.h>
+#include <stdint.h>
+
+/**
+ * Create a nul-terminated C string containing the formatted representation of a `struct timeval`.
+ *
+ * The minimum length of the result is 8 characters consisting of the `struct timeval`
+ * formatted as a decimal string consisting of the number of seconds since midnight (0 hour), January 1, 1970.
+ *
+ * @param [in] timeval The instance of the struct `timeval` to convert to a C string.
+ * @return An allocated, null-terminated C string that must be freed via {@link parcMemory_Deallocate()}.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval timeval;
+ * gettimeofday(&timeval, NULL);
+ *
+ * char *string = parcTime_TimevalAsString(timeval);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ */
+char *parcTime_TimevalAsString(struct timeval timeval);
+
+/**
+ * Format an ISO8601 date from the given struct timeval into the given character array, @p result.
+ *
+ * @param [in] utcTime A pointer to a valid struct timeval instance with the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval theTime;
+ * gettimeofday(&theTime, NULL);
+ *
+ * char result[64];
+ * parcTime_TimevalAsISO8601(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimevalAsISO8601(const struct timeval *utcTime, char *result);
+
+/**
+ * Format an RFC3339 compliant date from the given struct timeval into the given character array.
+ *
+ * @param [in] utcTime A pointer to a valid struct timeval instance with the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval theTime;
+ * gettimeofday(&theTime, NULL);
+ *
+ * char result[64];
+ * parcTime_TimevalAsRFC3339(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimevalAsRFC3339(const struct timeval *utcTime, char *result);
+
+/**
+ * Format an ISO8601 date from the given `time_t` value into the given character array, @p result.
+ *
+ * @param [in] utcTime `time_t` value representing the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * time_t theTime = time(0);
+ *
+ * char result[64];
+ * parcTime_TimeAsISO8601(theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimeAsISO8601(const time_t utcTime, char *result);
+
+/**
+ * Format the current time as an ISO8601 date into the given character array, @p result.
+ *
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * char result[64];
+ * parcTime_NowAsISO8601(theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_NowAsISO8601(char *result);
+
+/**
+ * Format an RFC3339 compliant date from the given `time_t` value into the given character array.
+ *
+ * @param [in] utcTime `time_t` value of the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval theTime;
+ * time_t theTime = time(0);
+ *
+ * char result[64];
+ * parcTime_TimeAsRFC3339(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimeAsRFC3339(const time_t utcTime, char *result);
+
+/**
+ * Format the current time as an RFC3339 compliant date into the given character array.
+ *
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * char result[64];
+ * parcTime_NowAsRFC3339(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_NowAsRFC3339(char *result);
+
+/**
+ * Add two `struct timeval` values together.
+ *
+ * @param [in] addend1 The first value.
+ * @param [in] addend2 The second value.
+ *
+ * @return The sum of the first and second values.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval now;
+ * gettimeofday(&now, NULL);
+ *
+ * struct timeval theEnd = parcTime_TimevalAdd(&now, timeout);
+ * }
+ * @endcode
+ */
+struct timeval parcTime_TimevalAdd(const struct timeval *addend1, const struct timeval *addend2);
+
+/**
+ * Subtract two `struct timeval` values.
+ *
+ * @param [in] minuend The number from which the subtrahend is to be subtracted.
+ * @param [in] subtrahend The subtrahend.
+ *
+ * @return The difference between the first and second values.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval now;
+ * gettimeofday(&now, NULL);
+ *
+ * struct timeval result = parcTime_TimevalSubtract(&now, timeout);
+ * }
+ * @endcode
+ */
+struct timeval parcTime_TimevalSubtract(const struct timeval *minuend, const struct timeval *subtrahend);
+
+/**
+ * The current time as a `struct timeval`.
+ *
+ * @return The current time as a `struct timeval`.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * struct timeval now = parcTime_NowTimeval();
+ * }
+ * @endcode
+ */
+struct timeval parcTime_NowTimeval(void);
+
+/**
+ * The current time in microseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * @return The current time in microseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * uint64_t now = parcTime_NowMicroseconds();
+ * }
+ * @endcode
+ */
+uint64_t parcTime_NowMicroseconds(void);
+
+/**
+ * The current time in nanoseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * @return The current time in nanoseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * uint64_t now = parcTime_NowNanoseconds();
+ * }
+ * @endcode
+ */
+uint64_t parcTime_NowNanoseconds(void);
+#endif // libparc_parc_Time_h
diff --git a/libparc/parc/algol/parc_TreeMap.c b/libparc/parc/algol/parc_TreeMap.c
new file mode 100755
index 00000000..9c776b30
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeMap.c
@@ -0,0 +1,1120 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include "parc_TreeMap.h"
+#include "parc_ArrayList.h"
+#include "parc_KeyValue.h"
+
+#include <parc/algol/parc_Memory.h>
+
+#define RED 1
+#define BLACK 0
+
+#define ASSERT_INVARIANTS
+
+struct treemap_node;
+typedef struct treemap_node _RBNode;
+
+struct treemap_node {
+ _RBNode *leftChild;
+ _RBNode *rightChild;
+ _RBNode *parent;
+ PARCKeyValue *element;
+ int color;
+};
+
+struct parc_treemap {
+ _RBNode *root;
+ _RBNode *nil;
+ int size;
+ PARCTreeMap_CustomCompare *customCompare;
+};
+
+typedef void (rbRecursiveFunc)(_RBNode *node, PARCObject *data);
+
+static void
+_rbNodeFree(_RBNode *node)
+{
+ if (node->element != NULL) {
+ parcKeyValue_Release(&(node->element));
+ }
+ parcMemory_Deallocate((void **) &node);
+}
+
+static void
+_rbNodeFreeRecursive(PARCTreeMap *tree, _RBNode *node)
+{
+ if (node->leftChild != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->leftChild);
+ }
+ if (node->rightChild != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->rightChild);
+ }
+ // We descended on both branches, now free myself.
+ _rbNodeFree(node);
+ tree->size--;
+}
+
+// Run a function on all nodes in the tree, in order
+static void
+_rbNodeRecursiveRun(PARCTreeMap *tree, _RBNode *node, rbRecursiveFunc *func, PARCObject *data)
+{
+ if (node->leftChild != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->leftChild, func, data);
+ }
+ func(node, data);
+ if (node->rightChild != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->rightChild, func, data);
+ }
+}
+
+
+static _RBNode *
+_rbMinRelativeNode(const PARCTreeMap *tree, _RBNode *startNode)
+{
+ _RBNode *searchNode = startNode;
+
+ // Let's get to the bottom left
+ while (searchNode->leftChild != tree->nil) {
+ searchNode = searchNode->leftChild;
+ }
+
+ return searchNode;
+}
+
+static _RBNode *
+_rbMaxRelativeNode(const PARCTreeMap *tree, _RBNode *startNode)
+{
+ _RBNode *searchNode = startNode;
+
+ // Let's get to the bottom left
+ while (searchNode->rightChild != tree->nil) {
+ searchNode = searchNode->rightChild;
+ }
+
+ return searchNode;
+}
+
+static _RBNode *
+_rbNextNode(const PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *searchNode = node;
+ if (searchNode->rightChild != tree->nil) {
+ searchNode = _rbMinRelativeNode(tree, searchNode->rightChild);
+ } else {
+ _RBNode *parent = searchNode->parent;
+ while (parent != tree->nil) {
+ if (parent->leftChild == searchNode) {
+ break;
+ }
+ searchNode = parent;
+ parent = searchNode->parent;
+ }
+ searchNode = parent;
+ }
+
+ return searchNode;
+}
+
+static _RBNode *
+_rbPreviousNode(const PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *searchNode = node;
+ if (searchNode->leftChild != tree->nil) {
+ searchNode = _rbMaxRelativeNode(tree, searchNode->leftChild);
+ } else {
+ _RBNode *parent = searchNode->parent;
+ while (parent != tree->nil) {
+ if (parent->rightChild == searchNode) {
+ break;
+ }
+ searchNode = parent;
+ parent = searchNode->parent;
+ }
+ searchNode = parent;
+ }
+
+ return searchNode;
+}
+
+
+/**
+ * Create a node
+ * Set the parent and children to tree->nil.
+ * If we are creating the nil node this might leave garbage there (if not preset to NULL).
+ */
+static _RBNode *
+_rbNodeCreate(PARCTreeMap *tree, int color)
+{
+ _RBNode *node = parcMemory_AllocateAndClear(sizeof(_RBNode));
+ assertNotNull(node, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_RBNode));
+ node->color = color;
+ node->leftChild = tree->nil;
+ node->rightChild = tree->nil;
+ node->parent = tree->nil;
+ return node;
+}
+
+static void
+_rbNodeSetColor(_RBNode *node, uint8_t color)
+{
+ node->color = color;
+}
+
+static int
+_rbNodeColor(const _RBNode *node)
+{
+ return node->color;
+}
+
+static bool
+_rbNodeIsEqual(const PARCTreeMap *tree, const _RBNode *node, const PARCObject *key)
+{
+ bool result = false;
+ if (node->element != NULL) {
+ if (tree->customCompare != NULL) {
+ result = (tree->customCompare(parcKeyValue_GetKey(node->element), key) == 0);
+ } else {
+ result = parcObject_Equals(parcKeyValue_GetKey(node->element), key);
+ }
+ }
+ return result;
+}
+
+static bool
+_rbNodeIsGreaterThan(const PARCTreeMap *tree, const _RBNode *node, const PARCObject *key)
+{
+ bool result = false;
+ if (node->element != NULL) {
+ if (tree->customCompare != NULL) {
+ result = (tree->customCompare(parcKeyValue_GetKey(node->element), key) > 0);
+ } else {
+ result = (parcObject_Compare(parcKeyValue_GetKey(node->element), key) > 0);
+ }
+ }
+ return result;
+}
+
+static _RBNode *
+_rbFindNode(const PARCTreeMap *tree, _RBNode *startNode, const PARCObject *key)
+{
+ _RBNode *result = NULL;
+ _RBNode *node = startNode;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ result = node;
+ break;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->leftChild;
+ } else {
+ node = node->rightChild;
+ }
+ }
+ }
+ return result;
+}
+
+
+static void
+_rbNodeUpdate(_RBNode *treeNode, _RBNode *newNode)
+{
+ // Free old values
+ if (treeNode->element != NULL) {
+ parcKeyValue_Release(&treeNode->element);
+ }
+
+ treeNode->element = parcKeyValue_Acquire(newNode->element);
+ _rbNodeFree(newNode);
+}
+
+static void
+_rbNodeRotateLeft(PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *subroot = node->rightChild;
+ node->rightChild = subroot->leftChild;
+ if (node->rightChild != tree->nil) {
+ node->rightChild->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->leftChild == node) {
+ // node was a left child
+ subroot->parent->leftChild = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->rightChild = subroot;
+ }
+ }
+
+ subroot->leftChild = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeRotateRight(PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *subroot = node->leftChild;
+ node->leftChild = subroot->rightChild;
+ if (node->leftChild != tree->nil) {
+ node->leftChild->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->leftChild == node) {
+ // node was a left child
+ subroot->parent->leftChild = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->rightChild = subroot;
+ }
+ }
+
+ subroot->rightChild = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeFix(PARCTreeMap *tree, _RBNode *startNode)
+{
+ _RBNode *node = startNode;
+ _RBNode *uncle;
+ while (_rbNodeColor(node->parent) == RED) {
+ if (node->parent->parent->leftChild == node->parent) {
+ uncle = node->parent->parent->rightChild;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->rightChild == node) {
+ node = node->parent;
+ _rbNodeRotateLeft(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateRight(tree, node->parent->parent);
+ }
+ } else {
+ uncle = node->parent->parent->leftChild;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->leftChild == node) {
+ node = node->parent;
+ _rbNodeRotateRight(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent->parent);
+ }
+ }
+ }
+ _rbNodeSetColor(tree->root, BLACK);
+}
+
+static void
+_rbNodeAssertNodeInvariants(_RBNode *node, PARCObject *data)
+{
+ PARCTreeMap *tree = (PARCTreeMap *) data;
+ assertNotNull(node->parent, "Node has NULL parent");
+ assertNotNull(node->leftChild, "Left child NULL");
+ assertNotNull(node->rightChild, "Richt child NULL");
+ if (node != tree->root) {
+ assertTrue(node->parent != tree->nil, "Paren't can't be nill for node!");
+ // Don't need to compare to parent, they compared to us
+ }
+ assertNotNull(node->element, "We have a null element!!");
+ assertNotNull(parcKeyValue_GetKey(node->element), "We have a null key!!");
+ assertNotNull(parcKeyValue_GetValue(node->element), "We have a null value!!");
+ if (node->leftChild != tree->nil) {
+ if (tree->customCompare != NULL) {
+ assertTrue(tree->customCompare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->leftChild->element)) > 0, "Left child not smaller?");
+ } else {
+ assertTrue(parcObject_Compare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->leftChild->element)) > 0, "Left child not smaller?");
+ }
+ }
+ if (node->rightChild != tree->nil) {
+ if (tree->customCompare != NULL) {
+ assertTrue(tree->customCompare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->rightChild->element)) < 0, "Right child not bigger?");
+ } else {
+ assertTrue(parcObject_Compare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->rightChild->element)) < 0, "Right child not bigger?");
+ }
+ }
+}
+
+static
+void
+_rbNodeAssertTreeInvariants(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree is null!");
+ assertTrue(tree->size >= 0, "Tree has negative size");
+ if (tree->size != 0) {
+ assertTrue(tree->root != tree->nil, "Tree size = %d > 0 but root is nil", tree->size);
+ assertNotNull(tree->root, "Tree size > 0 but root is NULL");
+#ifdef ASSERT_INVARIANTS
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, _rbNodeAssertNodeInvariants, (PARCObject *) tree);
+#endif
+ }
+}
+
+static void
+_rbNodeFixDelete(PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *fixNode;
+
+ while ((node != tree->root) && (_rbNodeColor(node) == BLACK)) {
+ _rbNodeAssertTreeInvariants(tree);
+ if (node == node->parent->leftChild) {
+ fixNode = node->parent->rightChild;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent);
+ fixNode = node->parent->rightChild;
+ }
+ if ((_rbNodeColor(fixNode->leftChild) == BLACK) &&
+ (_rbNodeColor(fixNode->rightChild) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->rightChild) == BLACK) {
+ _rbNodeSetColor(fixNode->leftChild, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateRight(tree, fixNode);
+ fixNode = node->parent->rightChild;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->rightChild, BLACK);
+ _rbNodeRotateLeft(tree, node->parent);
+ node = tree->root;
+ }
+ } else {
+ fixNode = node->parent->leftChild;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateRight(tree, node->parent);
+ fixNode = node->parent->leftChild;
+ }
+ if ((_rbNodeColor(fixNode->leftChild) == BLACK) &&
+ (_rbNodeColor(fixNode->rightChild) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->leftChild) == BLACK) {
+ _rbNodeSetColor(fixNode->rightChild, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateLeft(tree, fixNode);
+ fixNode = node->parent->leftChild;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->leftChild, BLACK);
+ _rbNodeRotateRight(tree, node->parent);
+ node = tree->root;
+ }
+ }
+ }
+
+ _rbNodeSetColor(node, BLACK);
+}
+
+// Remove the node from the tree.
+// The node must be part of a tree (with parents and children)
+static void
+_rbNodeRemove(PARCTreeMap *tree, _RBNode *node)
+{
+ _rbNodeAssertTreeInvariants(tree);
+ _RBNode *fixupNode;
+ int deleteNodeColor = _rbNodeColor(node);
+ if (node->leftChild == tree->nil) {
+ if (node->rightChild == tree->nil) {
+ // ---- We have no children ----
+ if (tree->root == node) {
+ tree->root = tree->nil;
+ } else {
+ if (node->parent->leftChild == node) {
+ node->parent->leftChild = tree->nil;
+ } else {
+ node->parent->rightChild = tree->nil;
+ }
+ }
+ fixupNode = tree->nil;
+ fixupNode->parent = node->parent;
+ } else {
+ // ---- We only have right child, move up ----
+ if (tree->root == node) {
+ tree->root = node->rightChild;
+ } else {
+ if (node->parent->leftChild == node) {
+ node->parent->leftChild = node->rightChild;
+ } else {
+ node->parent->rightChild = node->rightChild;
+ }
+ }
+ fixupNode = node->rightChild;
+ node->rightChild->parent = node->parent;
+ }
+ } else {
+ if (node->rightChild == tree->nil) {
+ // ---- We only have left child, move up ----
+ if (tree->root == node) {
+ tree->root = node->leftChild;
+ } else {
+ if (node->parent->leftChild == node) {
+ node->parent->leftChild = node->leftChild;
+ } else {
+ node->parent->rightChild = node->leftChild;
+ }
+ }
+ node->leftChild->parent = node->parent;
+ fixupNode = node->leftChild;
+ } else {
+ // ---- We have 2 children, move our successor to our location ----
+ _RBNode *successor = node->rightChild;
+ while (successor->leftChild != tree->nil) {
+ successor = successor->leftChild;
+ }
+ deleteNodeColor = _rbNodeColor(successor);
+
+ // Remove successor, it has no left child
+ if (successor == successor->parent->leftChild) {
+ successor->parent->leftChild = successor->rightChild;
+ } else {
+ successor->parent->rightChild = successor->rightChild;
+ }
+ successor->rightChild->parent = successor->parent;
+
+ fixupNode = successor->rightChild;
+
+ if (node->parent == tree->nil) {
+ tree->root = successor;
+ } else if (node->parent->leftChild == node) {
+ node->parent->leftChild = successor;
+ } else {
+ node->parent->rightChild = successor;
+ }
+ successor->parent = node->parent;
+ successor->leftChild = node->leftChild;
+ node->leftChild->parent = successor;
+ successor->rightChild = node->rightChild;
+ node->rightChild->parent = successor;
+
+ _rbNodeSetColor(successor, _rbNodeColor(node));
+
+ if (successor->parent == tree->nil) {
+ tree->root = successor;
+ }
+ }
+ }
+ tree->size--;
+
+ // Fix the red-blackness
+ _rbNodeAssertTreeInvariants(tree);
+ if (deleteNodeColor == BLACK) {
+ _rbNodeFixDelete(tree, fixupNode);
+ }
+ _rbNodeAssertTreeInvariants(tree);
+}
+
+static void
+_parcTreeMap_Destroy(PARCTreeMap **treePointer)
+{
+ assertNotNull(treePointer, "pointer to pointer to tree can't be null");
+ assertNotNull(*treePointer, "pointer to tree can't be null");
+ _rbNodeAssertTreeInvariants(*treePointer);
+
+ if ((*treePointer)->size > 0) {
+ // If we have any elements in the tree, free them
+ _rbNodeFreeRecursive(*treePointer, (*treePointer)->root);
+ }
+
+ // Free the nil element
+ parcMemory_Deallocate((void **) &((*treePointer)->nil));
+}
+
+
+parcObject_ExtendPARCObject(PARCTreeMap, _parcTreeMap_Destroy, parcTreeMap_Copy, NULL, parcTreeMap_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcTreeMap, PARCTreeMap);
+
+parcObject_ImplementRelease(parcTreeMap, PARCTreeMap);
+
+PARCTreeMap *
+parcTreeMap_CreateCustom(PARCTreeMap_CustomCompare *customCompare)
+{
+ PARCTreeMap *tree = parcObject_CreateInstance(PARCTreeMap);
+ assertNotNull(tree, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCTreeMap));
+ tree->nil = _rbNodeCreate(tree, BLACK);
+ tree->nil->leftChild = tree->nil;
+ tree->nil->rightChild = tree->nil;
+ tree->nil->parent = tree->nil;
+ tree->root = tree->nil;
+ tree->customCompare = customCompare;
+ tree->size = 0;
+ return tree;
+}
+
+PARCTreeMap *
+parcTreeMap_Create(void)
+{
+ return parcTreeMap_CreateCustom(NULL);
+}
+
+void
+parcTreeMap_Put(PARCTreeMap *tree, const PARCObject *key, const PARCObject *value)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+ assertNotNull(value, "Value can't be NULL");
+
+ _RBNode *newNode = _rbNodeCreate(tree, RED);
+ _RBNode *parent = tree->nil;
+ _RBNode *node;
+
+ // Set the value for the created node
+ PARCKeyValue *element = parcKeyValue_Create(key, value);
+ newNode->element = element;
+
+ // Start at the top
+ node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ parent = node;
+ if (_rbNodeIsEqual(tree, node, key)) {
+ // We're trying to insert the same value
+ _rbNodeUpdate(node, newNode);
+ return;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ // The key is smaller
+ node = node->leftChild;
+ } else {
+ node = node->rightChild;
+ }
+ }
+ }
+
+ // We're at the bottom.
+ // node is nil (a leaf)
+ newNode->parent = parent;
+ if (parent == tree->nil) {
+ // nil is our parent, we are the root
+ tree->root = newNode;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, parent, key)) {
+ parent->leftChild = newNode;
+ } else {
+ parent->rightChild = newNode;
+ }
+ }
+
+ // We have inserted one node.
+ tree->size++;
+
+ // We have a correct tree. But we need to regain the red-black property.
+ _rbNodeFix(tree, newNode);
+
+ _rbNodeAssertTreeInvariants(tree);
+}
+
+PARCObject *
+parcTreeMap_Get(PARCTreeMap *tree, const PARCObject *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCObject *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+
+ if (node != NULL) {
+ result = parcKeyValue_GetValue(node->element);
+ }
+
+ return result;
+}
+
+// Return value, remove from tree
+PARCObject *
+parcTreeMap_Remove(PARCTreeMap *tree, const PARCObject *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCObject *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+
+ if (node != NULL) {
+ _rbNodeRemove(tree, node);
+ result = parcObject_Acquire(parcKeyValue_GetValue(node->element));
+ _rbNodeFree(node);
+ }
+
+ // We didn't find the node
+
+ _rbNodeAssertTreeInvariants(tree);
+
+ return result;
+}
+
+// remove from tree and destroy
+void
+parcTreeMap_RemoveAndRelease(PARCTreeMap *tree, const PARCObject *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+
+ if (node != NULL) {
+ _rbNodeRemove(tree, node);
+ _rbNodeFree(node);
+ }
+
+ _rbNodeAssertTreeInvariants(tree);
+}
+
+PARCKeyValue *
+parcTreeMap_GetLastEntry(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+ _RBNode *node = tree->root;
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ // Let's get to the bottom right of the tree to find the largest
+ while (node->rightChild != tree->nil) {
+ node = node->rightChild;
+ }
+
+ return node->element;
+}
+
+PARCObject *
+parcTreeMap_GetLastKey(const PARCTreeMap *tree)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *entry = parcTreeMap_GetLastEntry(tree);
+ if (entry != NULL) {
+ result = parcKeyValue_GetKey(entry);
+ }
+
+ return result;
+}
+
+PARCKeyValue *
+parcTreeMap_GetFirstEntry(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ _RBNode *node = _rbMinRelativeNode(tree, tree->root);
+
+ return node->element;
+}
+
+PARCObject *
+parcTreeMap_GetFirstKey(const PARCTreeMap *tree)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *entry = parcTreeMap_GetFirstEntry(tree);
+ if (entry != NULL) {
+ result = parcKeyValue_GetKey(entry);
+ }
+
+ return result;
+}
+
+PARCKeyValue *
+parcTreeMap_GetHigherEntry(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCKeyValue *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+ if (node != NULL) {
+ node = _rbNextNode(tree, node);
+ if (node != NULL) {
+ result = node->element;
+ }
+ }
+
+ return result;
+}
+
+PARCObject *
+parcTreeMap_GetHigherKey(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *kv = parcTreeMap_GetHigherEntry(tree, key);
+ if (kv != NULL) {
+ result = parcKeyValue_GetKey(kv);
+ }
+
+ return result;
+}
+
+PARCKeyValue *
+parcTreeMap_GetLowerEntry(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCKeyValue *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+ if (node != NULL) {
+ node = _rbPreviousNode(tree, node);
+ if (node != NULL) {
+ result = node->element;
+ }
+ }
+
+ return result;
+}
+
+PARCObject *
+parcTreeMap_GetLowerKey(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *kv = parcTreeMap_GetLowerEntry(tree, key);
+ if (kv != NULL) {
+ result = parcKeyValue_GetKey(kv);
+ }
+
+ return result;
+}
+
+
+size_t
+parcTreeMap_Size(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ return tree->size;
+}
+
+static void
+_rbAddKeyToList(_RBNode *node, PARCList *list)
+{
+ parcList_Add(list, parcObject_Acquire(parcKeyValue_GetKey(node->element)));
+}
+
+static void
+_rbAddalueToList(_RBNode *node, PARCList *list)
+{
+ parcList_Add(list, parcObject_Acquire(parcKeyValue_GetValue(node->element)));
+}
+
+static void
+_rbAddElementToList(_RBNode *node, PARCList *list)
+{
+ parcList_Add(list, parcObject_Acquire(node->element));
+}
+
+PARCList *
+parcTreeMap_AcquireKeys(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCList *keys = parcList(parcArrayList_Create_Capacity((bool (*)(void *x, void *y))parcObject_Equals,
+ (void (*)(void **))parcObject_Release, tree->size),
+ PARCArrayListAsPARCList);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, (rbRecursiveFunc *) _rbAddKeyToList, keys);
+ }
+ return keys;
+}
+
+PARCList *
+parcTreeMap_AcquireValues(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCList *values = parcList(parcArrayList_Create_Capacity((bool (*)(void *x, void *y))parcObject_Equals,
+ (void (*)(void **))parcObject_Release, tree->size),
+ PARCArrayListAsPARCList);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, (rbRecursiveFunc *) _rbAddalueToList, values);
+ }
+ return values;
+}
+
+static PARCList *
+_parcTreeMap_Elements(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCList *elements = parcList(parcArrayList_Create_Capacity((bool (*)(void *x, void *y))parcObject_Equals,
+ (void (*)(void **))parcObject_Release, tree->size),
+ PARCArrayListAsPARCList);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, (rbRecursiveFunc *) _rbAddElementToList, elements);
+ }
+ return elements;
+}
+
+bool
+parcTreeMap_Equals(const PARCTreeMap *tree1, const PARCTreeMap *tree2)
+{
+ _rbNodeAssertTreeInvariants(tree1);
+ _rbNodeAssertTreeInvariants(tree2);
+ assertNotNull(tree1, "Tree can't be NULL");
+ assertNotNull(tree2, "Tree can't be NULL");
+
+ bool result = false;
+
+ PARCList *keys1 = parcTreeMap_AcquireKeys(tree1);
+ PARCList *keys2 = parcTreeMap_AcquireKeys(tree2);
+ size_t length1 = parcList_Size(keys1);
+ size_t length2 = parcList_Size(keys2);
+
+ if (length1 == length2) {
+ result = true;
+ for (size_t i = 0; i < length1; i++) {
+ if (!parcObject_Equals(parcList_GetAtIndex(keys1, i), parcList_GetAtIndex(keys2, i))) {
+ result = false;
+ break;
+ }
+ }
+ if (result) {
+ PARCList *values1 = parcTreeMap_AcquireValues(tree1);
+ PARCList *values2 = parcTreeMap_AcquireValues(tree2);
+ size_t s1 = parcList_Size(values1);
+ size_t s2 = parcList_Size(values2);
+ if (s1 == s2) {
+ for (size_t i = 0; i < s1; i++) {
+ PARCObject *value1 = parcList_GetAtIndex(values1, i);
+ PARCObject *value2 = parcList_GetAtIndex(values2, i);
+ if (!parcObject_Equals(value1, value2)) {
+ result = false;
+ break;
+ }
+ }
+ }
+ parcList_Release(&values1);
+ parcList_Release(&values2);
+ }
+ }
+
+ parcList_Release(&keys1);
+ parcList_Release(&keys2);
+ return result;
+}
+
+
+/*
+ * This is a simple implementation of Copy that goes through the list of keys and values.
+ */
+PARCTreeMap *
+parcTreeMap_Copy(const PARCTreeMap *sourceTree)
+{
+ _rbNodeAssertTreeInvariants(sourceTree);
+ assertNotNull(sourceTree, "Tree can't be NULL");
+
+ PARCObject *keySource;
+ PARCObject *keyCopy;
+ PARCObject *valueSource;
+ PARCObject *valueCopy;
+
+ PARCTreeMap *treeCopy = parcTreeMap_CreateCustom(sourceTree->customCompare);
+
+ PARCList *keys = parcTreeMap_AcquireKeys(sourceTree);
+ PARCList *values = parcTreeMap_AcquireValues(sourceTree);
+
+ size_t total_keys = parcList_Size(keys);
+
+ for (size_t i = 0; i < total_keys; i++) {
+ keySource = parcList_GetAtIndex(keys, i);
+ valueSource = parcList_GetAtIndex(values, i);
+
+ keyCopy = parcObject_Copy(keySource);
+ valueCopy = parcObject_Copy(valueSource);
+
+ parcTreeMap_Put(treeCopy, keyCopy, valueCopy);
+ parcObject_Release(&keyCopy);
+ parcObject_Release(&valueCopy);
+ }
+
+ parcList_Release(&keys);
+ parcList_Release(&values);
+
+ return treeCopy;
+}
+
+////// Iterator Support //////
+
+typedef struct {
+ PARCTreeMap *map;
+ PARCList *list;
+ size_t currentIndex;
+ PARCKeyValue *currentElement;
+} _PARCTreeMapIterator;
+
+static _PARCTreeMapIterator *
+_parcTreeMapIterator_Init(PARCTreeMap *map)
+{
+ _PARCTreeMapIterator *state = parcMemory_AllocateAndClear(sizeof(_PARCTreeMapIterator));
+
+ if (state != NULL) {
+ state->map = map;
+ state->list = _parcTreeMap_Elements(map);
+ state->currentIndex = 0;
+ state->currentElement = parcList_GetAtIndex(state->list, 0);
+ trapOutOfMemoryIf(state->list == NULL, "Cannot create parcList");
+ }
+
+ return state;
+}
+
+static bool
+_parcTreeMapIterator_Fini(PARCTreeMap *map __attribute__((unused)), _PARCTreeMapIterator *state __attribute__((unused)))
+{
+ parcList_Release(&state->list);
+ parcMemory_Deallocate(&state);
+ return true;
+}
+
+static _PARCTreeMapIterator *
+_parcTreeMapIterator_Next(PARCTreeMap *map __attribute__((unused)), _PARCTreeMapIterator *state)
+{
+ state->currentElement = parcList_GetAtIndex(state->list, state->currentIndex);
+ ++state->currentIndex;
+ return state;
+}
+
+static void
+_parcTreeMapIterator_Remove(PARCTreeMap *map, _PARCTreeMapIterator **statePtr)
+{
+ _PARCTreeMapIterator *state = *statePtr;
+
+ parcTreeMap_RemoveAndRelease(map, parcKeyValue_GetKey(state->currentElement));
+}
+
+static bool
+_parcTreeMapIterator_HasNext(PARCTreeMap *map __attribute__((unused)), _PARCTreeMapIterator *state)
+{
+ return (parcList_Size(state->list) > state->currentIndex);
+}
+
+static PARCObject *
+_parcTreeMapIterator_Element(PARCTreeMap *map __attribute__((unused)), const _PARCTreeMapIterator *state)
+{
+ return state->currentElement;
+}
+
+static PARCObject *
+_parcTreeMapIterator_ElementValue(PARCTreeMap *map __attribute__((unused)), const _PARCTreeMapIterator *state)
+{
+ return parcKeyValue_GetValue(state->currentElement);
+}
+
+static PARCObject *
+_parcTreeMapIterator_ElementKey(PARCTreeMap *map __attribute__((unused)), const _PARCTreeMapIterator *state)
+{
+ return parcKeyValue_GetKey(state->currentElement);
+}
+
+PARCIterator *
+parcTreeMap_CreateValueIterator(PARCTreeMap *treeMap)
+{
+ PARCIterator *iterator = parcIterator_Create(treeMap,
+ (void *(*)(PARCObject *))_parcTreeMapIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcTreeMapIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Next,
+ (void (*)(PARCObject *, void **))_parcTreeMapIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_ElementValue,
+ (void (*)(PARCObject *, void *))_parcTreeMapIterator_Fini,
+ NULL);
+
+ return iterator;
+}
+
+
+PARCIterator *
+parcTreeMap_CreateKeyIterator(PARCTreeMap *treeMap)
+{
+ PARCIterator *iterator = parcIterator_Create(treeMap,
+ (void *(*)(PARCObject *))_parcTreeMapIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcTreeMapIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Next,
+ (void (*)(PARCObject *, void **))_parcTreeMapIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_ElementKey,
+ (void (*)(PARCObject *, void *))_parcTreeMapIterator_Fini,
+ NULL);
+
+ return iterator;
+}
+
+PARCIterator *
+parcTreeMap_CreateKeyValueIterator(PARCTreeMap *treeMap)
+{
+ PARCIterator *iterator = parcIterator_Create(treeMap,
+ (void *(*)(PARCObject *))_parcTreeMapIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcTreeMapIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Next,
+ (void (*)(PARCObject *, void **))_parcTreeMapIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Element,
+ (void (*)(PARCObject *, void *))_parcTreeMapIterator_Fini,
+ NULL);
+
+ return iterator;
+}
diff --git a/libparc/parc/algol/parc_TreeMap.h b/libparc/parc/algol/parc_TreeMap.h
new file mode 100755
index 00000000..5f0ed8d8
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeMap.h
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_TreeMap.h
+ * @ingroup datastructures
+ * @brief A Red-Black tree containing PARCObject keys and values.
+ *
+ * The map is sorted according to the natural ordering of its keys,
+ * or by a comparator function provided at creation time, depending on which constructor is used.
+ *
+ */
+#ifndef libparc_parc_TreeMap_h
+#define libparc_parc_TreeMap_h
+
+#include <stdlib.h>
+
+#include "parc_Object.h"
+#include "parc_KeyValue.h"
+#include "parc_List.h"
+#include "parc_Iterator.h"
+
+struct parc_treemap;
+typedef struct parc_treemap PARCTreeMap;
+
+/**
+ * Definition of a custom funcion to compare two keys. A function of
+ * this signature can be provided to CreateCustom(...) constructor to
+ * override the default parcObject_Compare(...) for comparing key
+ * objects. This will be used during all internal comparisons.
+ *
+ * @param [in] key1 The first key to compare
+ * @param [in] key2 The second key to compare
+ *
+ * @return A signum comparison. negative if key1 is smaller than key2,
+ * 0 if equal, positive if key1 is bigger.
+ *
+ * Example:
+ * @code
+ * {
+ * int _compareKeys(const PARCObject *key1, const PARCObject *key2) {...}
+ *
+ * PARCTreeMap * tree1 = parcTreeMap_CreateCustom(_compareKeys);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+typedef int (PARCTreeMap_CustomCompare)(const PARCObject *key1, const PARCObject *key2);
+
+/**
+ * Create a standard `PARCTreeMap` that uses parcObject_Compare for
+ * comparisons.
+ *
+ * @return NULL Error allocating memory
+ * @return Non-NULL An initialized TreeMap
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCTreeMap *parcTreeMap_Create(void);
+
+/**
+ * Create a `PARCTreeMap` that uses the provided custom compare
+ * function for key comparisons.
+ *
+ * @param [in] customCompare A cusom function to compare keys (required)
+ * @return NULL Error allocating memory
+ * @return Non-NULL An initialized RedBlack tree
+ *
+ * Example:
+ * @code
+ * {
+ * int _compareKeys(const PARCObject *key1, const PARCObject *key2) {...}
+ *
+ * PARCTreeMap * tree1 = parcTreeMap_CreateCustom(_compareKeys);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCTreeMap *parcTreeMap_CreateCustom(PARCTreeMap_CustomCompare *customCompare);
+
+/**
+ * Acquire a reference to a `PARCTreeMap`.
+ *
+ * @param tree The tree reference to acquire.
+ *
+ * @return the acquired reference.
+ *
+ */
+PARCTreeMap *parcTreeMap_Acquire(const PARCTreeMap *tree);
+
+/**
+ * Release a reference to a `PARCTreeMap` object. If it is the last
+ * reference, the object itself is freed and the specified free
+ * function is invoked on the stored keys and values.
+ *
+ * @param [in,out] treePointer A pointer to a pointer to the `PARCTreeMap` to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+void parcTreeMap_Release(PARCTreeMap **treePointer);
+
+/**
+ * Insert a value into the `PARCTreeMap`. If the key exists in the
+ * tree then the new value will replace the old value. The old key and
+ * value will be released by the map and the map will acquire a
+ * reference to the new key and value. The key must not be NULL.
+ *
+ * @param [in, out] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key - This may not be NULL.
+ * @param [in] value A pointer to a value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * PARCObject *someKey = ...;
+ * PARCObject *someValue = ...;
+ *
+ * parcTreeMap_Put(tree1, someKey, someValue);
+ *
+ * parcObject_Release(&someKey);
+ * parcObject_Release(&someValue);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+void parcTreeMap_Put(PARCTreeMap *tree, const PARCObject *key, const PARCObject *value);
+
+/**
+ * Checks to see if a PARCTreeMap already contains a key.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key - This may not be NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * if (parcTreeMap_ContainsKey(tree1, someKey) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+bool parcTreeMap_ContainsKey(PARCTreeMap *tree, PARCObject *key);
+
+/**
+ * Get a value from a `PARCTreeMap`. If the key is not found in the
+ * tree NULL is returned. The returned value will still be owned by
+ * the tree.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *someValue = parcTreeMap_Get(tree1, someKey);
+ * if (someValue != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_Get(PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the first (smallest) key from a `PARCTreeMap`. The returned key
+ * will still be owned by the tree. If the tree is empty the function
+ * will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the smallest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = parcTreeMap_GetFirstKey(tree1);
+ * if (someKey != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetFirstKey(const PARCTreeMap *tree);
+
+/**
+ * Get the first entry (one with the smallest key) from a
+ * `PARCTreeMap`. The returned PARCKeyValue will still be owned by the
+ * tree. If the tree is empty the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the entry (a PARCKeyValue) with the smallest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCKeyValue *someEntry = parcTreeMap_GetFirstEntry(tree1);
+ * if (someEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetFirstEntry(const PARCTreeMap *tree);
+
+/**
+ * Get the last (largest) key from a `PARCTreeMap`. The returned key
+ * will still be owned by the tree. If the tree is empty the function
+ * will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the largest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = parcTreeMap_GetLastKey(tree1);
+ * if (someKey != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetLastKey(const PARCTreeMap *tree);
+
+/**
+ * Get the last entry (entry with the largest key) from a
+ * `PARCTreeMap`. The returned entry will still be owned by the tree.
+ * If the tree is empty the function will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the entry (a PARCKeyValue) with the largest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCKeyValue *lastEntry = parcTreeMap_GetLastEntry(tree1);
+ * if (lastEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetLastEntry(const PARCTreeMap *tree);
+
+/**
+ * Get the next largest key from a `PARCTreeMap`. The returned key
+ * will still be owned by the tree. If the tree is empty or the
+ * supplied key is the largest, the function will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the next key. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *nextKey = parcTreeMap_GetHigherKey(tree1, someKey);
+ * if (nextKey != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetHigherKey(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the entry with the next largest key from a `PARCTreeMap`. The
+ * returned entry will still be owned by the tree. If the tree is
+ * empty or the supplied key is the largest, the function will return
+ * NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the next entry (a PARCKeyValue). The caller
+ * does not own this return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCKeyValue *nextEntry = parcTreeMap_GetHigherEntry(tree1, someKey);
+ * if (nextEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetHigherEntry(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the previous key from a `PARCTreeMap`. The returned key will
+ * still be owned by the tree. If the tree is empty or the supplied
+ * key is the smallest in the tree, the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to an key
+ * @return A pointer to the previous key. The caller
+ * does not own this return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *previousKey = parcTreeMap_GetLowerKey(tree1, someKey);
+ * if (previousKey != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetLowerKey(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the entry with the next smallest key from a `PARCTreeMap`. The returned entry (a PARCKeyValue) will
+ * still be owned by the tree. If the tree is empty or the supplied
+ * key is the smallest in the tree, the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to an key
+ * @return A pointer to the previous entry (a PARCKeyValue). The caller
+ * does not own this return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCKeyValue *previousEntry = parcTreeMap_GetLowerKey(tree1, someKey);
+ * if (previousEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetLowerEntry(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Remove an entry from a `PARCTreeMap`. The entry will be removed
+ * from the tree and the tree's reference to the key will be
+ * released. The value will be returned and responsibility for
+ * releasing the reference to the value will transfer to the caller.
+ * The provided key will not be modified. If the key is not found in
+ * the tree, NULL is returned.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value or NULL. You will now own this value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *someValue = parcTreeMap_Remove(tree1, someKey);
+ * if (someValue != NULL) {
+ * ...
+ * parcObject_Release(&someValue);
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_Remove(PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Remove and destroy an entry from a `PARCTreeMap`. The entry along with
+ * it's key & value will be removed and released.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * parcTreeMap_RemoveAndRelease(tree1, someKey);
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+void parcTreeMap_RemoveAndRelease(PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the size (nuber of elements) of a `PARCTreeMap`.
+ *
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return size of the tree (number of elements).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * if (parcTreeMap_Size(tree1) > 0) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+size_t parcTreeMap_Size(const PARCTreeMap *tree);
+
+/**
+ * Get a PARCList of the keys from a `PARCTreeMap`. All keys will be
+ * valid keys in the `PARCTreeMap`. The caller will own the list of
+ * keys and should release it when done. The caller will not own the
+ * keys themselves. Note that if the tree is modified or destroyed
+ * the key pointers might no longer point to valid keys. The list of
+ * keys will be sorted as per the provided or key's default compare function.
+ *
+ * @param [in] tree A pointer to a `PARCTreeMap`.
+ * @return A list of (pointers to) keys.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCList *keys = parcTreeMap_AcquireKeys(tree1);
+ * for (size_t i=0; i < parcList_Size(keys); ++i) {
+ * ...
+ * }
+ *
+ * parcList_Release(&keys);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCList *parcTreeMap_AcquireKeys(const PARCTreeMap *tree);
+
+/**
+ * Get an PARCList of the values in this `PARCTreeMap`. All of these
+ * values will be valid in the `PARCTreeMap`. The caller will own the
+ * list of values and should release it when done. The list of values
+ * will be sorted as per the provided or key's default compare
+ * function.
+ *
+ * @param [in] tree A pointer to a `PARCTreeMap`.
+ * @return A list of (pointers to) values.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCList *values = parcTreeMap_AcquireValues(tree1);
+ * for (size_t i=0; i < parcList_Size(values); ++i) {
+ * ...
+ * }
+ *
+ * parcList_Release(&keys);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCList *parcTreeMap_AcquireValues(const PARCTreeMap *tree);
+
+/**
+ * Calculate if two `PARCTreeMap`s are equal.
+ *
+ * Two trees are equal if they have the same keys associated with the
+ * same values. The keys & values will be compared using the
+ * parcObject_Equals(...);
+ *
+ * @param [in] tree1 A pointer to a `PARCTreeMap`.
+ * @param [in] tree2 A pointer to another `PARCTreeMap`.
+ * @return true if the trees are equal, zero otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ * PARCTreeMap * tree2 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * if (parcTreeMap_Equals(tree1, tree2)) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * parcTreeMap_Release(&tree2);
+ * }
+ * @endcode
+ */
+bool parcTreeMap_Equals(const PARCTreeMap *tree1, const PARCTreeMap *tree2);
+
+/**
+ * Copy a TreeMap.
+ *
+ * This will create a completely new tree. It will copy every key and
+ * every value using parcObject_Copy(...).
+ *
+ * @param [in] sourceTree A pointer to a `PARCTreeMap` to be copied
+ * @return NULL Error copying the tree.
+ * @return Non-NULL A copy of the `PARCTreeMap`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * source_tree = parcTreeMap_Create(.....);
+ *
+ * ... operations on tree ...
+ *
+ * PARCTreeMap * tree_copy = parcTreeMap_Copy(source_tree);
+ *
+ * ... operations on tree ...
+ *
+ * parcTreeMap_Release(&source_tree);
+ * parcTreeMap_Release(&tree_copy);
+ * }
+ * @endcode
+ */
+PARCTreeMap *parcTreeMap_Copy(const PARCTreeMap *sourceTree);
+
+
+/**
+ * Create a new instance of PARCIterator that iterates through the keys of the specified `PARCTreeMap`.
+ * The returned iterator must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCTreeMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcTreeMap_CreateKeyIterator(myTreeMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcTreeMap_CreateKeyIterator(PARCTreeMap *tree);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the values of the specified `PARCTreeMap`.
+ * The returned iterator must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCTreeMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcTreeMap_CreateValueIterator(myTreeMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcTreeMap_CreateValueIterator(PARCTreeMap *tree);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the KeyValue elements of the specified `PARCTreeMap`.
+ * The returned iterator must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCTreeMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcTreeMap_CreateKeyValueIterator(myTreeMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcTreeMap_CreateKeyValueIterator(PARCTreeMap *tree);
+#endif // libparc_parc_TreeMap_h
diff --git a/libparc/parc/algol/parc_TreeRedBlack.c b/libparc/parc/algol/parc_TreeRedBlack.c
new file mode 100755
index 00000000..2d772555
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeRedBlack.c
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_TreeRedBlack.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#define RED 1
+#define BLACK 0
+
+struct redblack_node;
+typedef struct redblack_node Node;
+
+struct redblack_node {
+ Node *left_child;
+ Node *right_child;
+ Node *parent;
+ void *key;
+ void *value;
+ int color;
+};
+
+struct parc_tree_redblack {
+ Node *root;
+ Node *nil;
+ int size;
+ PARCTreeRedBlack_KeyCompare *keyCompare;
+ PARCTreeRedBlack_KeyFree *keyFree;
+ PARCTreeRedBlack_KeyCopy *keyCopy;
+ PARCTreeRedBlack_ValueFree *valueFree;
+ PARCTreeRedBlack_ValueEquals *valueEquals;
+ PARCTreeRedBlack_ValueCopy *valueCopy;
+};
+
+typedef void (rbRecursiveFunc)(Node *node, void *data);
+
+static void
+_rbNodeFree(PARCTreeRedBlack *tree, Node *node)
+{
+ if (tree->keyFree != NULL) {
+ tree->keyFree(&(node->key));
+ }
+ if (tree->valueFree != NULL) {
+ tree->valueFree(&(node->value));
+ }
+ parcMemory_Deallocate((void **) &node);
+}
+
+static void
+_rbNodeFreeRecursive(PARCTreeRedBlack *tree, Node *node)
+{
+ if (node->left_child != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->left_child);
+ }
+ if (node->right_child != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->right_child);
+ }
+ // We descended on both branches, now free myself.
+ _rbNodeFree(tree, node);
+ tree->size--;
+}
+
+// Run a function on all nodes in the tree, in order
+static void
+_rbNodeRecursiveRun(PARCTreeRedBlack *tree, Node *node, rbRecursiveFunc *func, void *data)
+{
+ if (node->left_child != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->left_child, func, data);
+ }
+ func(node, data);
+ if (node->right_child != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->right_child, func, data);
+ }
+}
+
+/**
+ * Create a node
+ * Set the parent and children to tree->nil.
+ * If we are creating the nil node this might leave garbage there (if not preset to NULL).
+ */
+static Node *
+_rbNodeCreate(PARCTreeRedBlack *tree, int color)
+{
+ Node *node = parcMemory_AllocateAndClear(sizeof(Node));
+ assertNotNull(node, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(Node));
+ node->color = color;
+ node->left_child = tree->nil;
+ node->right_child = tree->nil;
+ node->parent = tree->nil;
+ return node;
+}
+
+static void
+_rbNodeSetColor(Node *node, uint8_t color)
+{
+ node->color = color;
+}
+
+static int
+_rbNodeColor(const Node *node)
+{
+ return node->color;
+}
+
+static int
+_rbNodeIsEqual(const PARCTreeRedBlack *tree, const Node *node, const void *key)
+{
+ return (tree->keyCompare(node->key, key) == 0);
+}
+
+static int
+_rbNodeIsGreaterThan(const PARCTreeRedBlack *tree, const Node *node, const void *key)
+{
+ return (tree->keyCompare(node->key, key) > 0);
+}
+
+static void
+_rbNodeUpdate(PARCTreeRedBlack *tree, Node *treeNode, Node *newNode)
+{
+ // Free old values
+ if (tree->keyFree != NULL) {
+ tree->keyFree(&(treeNode->key));
+ }
+ if (tree->valueFree != NULL) {
+ tree->valueFree(&(treeNode->value));
+ }
+ treeNode->key = newNode->key;
+ treeNode->value = newNode->value;
+ parcMemory_Deallocate((void **) &newNode);
+}
+
+static void
+_rbNodeRotateLeft(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *subroot = node->right_child;
+ node->right_child = subroot->left_child;
+ if (node->right_child != tree->nil) {
+ node->right_child->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->left_child == node) {
+ // node was a left child
+ subroot->parent->left_child = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->right_child = subroot;
+ }
+ }
+
+ subroot->left_child = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeRotateRight(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *subroot = node->left_child;
+ node->left_child = subroot->right_child;
+ if (node->left_child != tree->nil) {
+ node->left_child->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->left_child == node) {
+ // node was a left child
+ subroot->parent->left_child = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->right_child = subroot;
+ }
+ }
+
+ subroot->right_child = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeFix(PARCTreeRedBlack *tree, Node *startNode)
+{
+ Node *node = startNode;
+ Node *uncle;
+ while (_rbNodeColor(node->parent) == RED) {
+ if (node->parent->parent->left_child == node->parent) {
+ uncle = node->parent->parent->right_child;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->right_child == node) {
+ node = node->parent;
+ _rbNodeRotateLeft(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateRight(tree, node->parent->parent);
+ }
+ } else {
+ uncle = node->parent->parent->left_child;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->left_child == node) {
+ node = node->parent;
+ _rbNodeRotateRight(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent->parent);
+ }
+ }
+ }
+ _rbNodeSetColor(tree->root, BLACK);
+}
+
+static void
+_rbNodeFixDelete(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *fixNode;
+
+ while ((node != tree->root) && (_rbNodeColor(node) == BLACK)) {
+ if (node == node->parent->left_child) {
+ fixNode = node->parent->right_child;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent);
+ fixNode = node->parent->right_child;
+ }
+ if ((_rbNodeColor(fixNode->left_child) == BLACK) &&
+ (_rbNodeColor(fixNode->right_child) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->right_child) == BLACK) {
+ _rbNodeSetColor(fixNode->left_child, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateRight(tree, fixNode);
+ fixNode = node->parent->right_child;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->right_child, BLACK);
+ _rbNodeRotateLeft(tree, node->parent);
+ node = tree->root;
+ }
+ } else {
+ fixNode = node->parent->left_child;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateRight(tree, node->parent);
+ fixNode = node->parent->left_child;
+ }
+ if ((_rbNodeColor(fixNode->left_child) == BLACK) &&
+ (_rbNodeColor(fixNode->right_child) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->left_child) == BLACK) {
+ _rbNodeSetColor(fixNode->right_child, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateLeft(tree, fixNode);
+ fixNode = node->parent->left_child;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->left_child, BLACK);
+ _rbNodeRotateRight(tree, node->parent);
+ node = tree->root;
+ }
+ }
+ }
+
+ _rbNodeSetColor(node, BLACK);
+}
+
+// Remove the node from the tree.
+// The node must be part of a tree (with parents and children)
+static void
+_rbNodeRemove(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *fixupNode;
+ int deleteNodeColor = _rbNodeColor(node);
+ if (node->left_child == tree->nil) {
+ if (node->right_child == tree->nil) {
+ // ---- We have no children ----
+ if (tree->root == node) {
+ tree->root = tree->nil;
+ } else {
+ if (node->parent->left_child == node) {
+ node->parent->left_child = tree->nil;
+ } else {
+ node->parent->right_child = tree->nil;
+ }
+ }
+ fixupNode = tree->nil;
+ fixupNode->parent = node->parent;
+ } else {
+ // ---- We only have right child, move up ----
+ if (tree->root == node) {
+ tree->root = node->right_child;
+ } else {
+ if (node->parent->left_child == node) {
+ node->parent->left_child = node->right_child;
+ } else {
+ node->parent->right_child = node->right_child;
+ }
+ }
+ fixupNode = node->right_child;
+ node->right_child->parent = node->parent;
+ }
+ } else {
+ if (node->right_child == tree->nil) {
+ // ---- We only have left child, move up ----
+ if (tree->root == node) {
+ tree->root = node->left_child;
+ } else {
+ if (node->parent->left_child == node) {
+ node->parent->left_child = node->left_child;
+ } else {
+ node->parent->right_child = node->left_child;
+ }
+ }
+ node->left_child->parent = node->parent;
+ fixupNode = node->left_child;
+ } else {
+ // ---- We have 2 children, move our successor to our location ----
+ Node *successor = node->right_child;
+ while (successor->left_child != tree->nil) {
+ successor = successor->left_child;
+ }
+ deleteNodeColor = _rbNodeColor(successor);
+
+ // Remove successor, it has no left child
+ if (successor == successor->parent->left_child) {
+ successor->parent->left_child = successor->right_child;
+ } else {
+ successor->parent->right_child = successor->right_child;
+ }
+ successor->right_child->parent = successor->parent;
+
+ fixupNode = successor->right_child;
+
+ if (node->parent == tree->nil) {
+ tree->root = successor;
+ } else if (node->parent->left_child == node) {
+ node->parent->left_child = successor;
+ } else {
+ node->parent->right_child = successor;
+ }
+ successor->parent = node->parent;
+ successor->left_child = node->left_child;
+ node->left_child->parent = successor;
+ successor->right_child = node->right_child;
+ node->right_child->parent = successor;
+
+ _rbNodeSetColor(successor, _rbNodeColor(node));
+
+ if (successor->parent == tree->nil) {
+ tree->root = successor;
+ }
+ }
+ }
+ tree->size--;
+
+ // Fix the red-blackness
+ if (deleteNodeColor == BLACK) {
+ _rbNodeFixDelete(tree, fixupNode);
+ }
+}
+
+
+PARCTreeRedBlack *
+parcTreeRedBlack_Create(PARCTreeRedBlack_KeyCompare *keyCompare,
+ PARCTreeRedBlack_KeyFree *keyFree,
+ PARCTreeRedBlack_KeyCopy *keyCopy,
+ PARCTreeRedBlack_ValueEquals *valueEquals,
+ PARCTreeRedBlack_ValueFree *valueFree,
+ PARCTreeRedBlack_ValueCopy *valueCopy)
+{
+ assertNotNull(keyCompare, "We need a key compare function");
+ PARCTreeRedBlack *tree = parcMemory_AllocateAndClear(sizeof(PARCTreeRedBlack));
+ assertNotNull(tree, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCTreeRedBlack));
+ tree->nil = _rbNodeCreate(tree, BLACK);
+ tree->nil->left_child = tree->nil;
+ tree->nil->right_child = tree->nil;
+ tree->nil->parent = tree->nil;
+ tree->root = tree->nil;
+ tree->keyCompare = keyCompare;
+ tree->keyFree = keyFree;
+ tree->keyCopy = keyCopy;
+ tree->valueEquals = valueEquals;
+ tree->valueFree = valueFree;
+ tree->valueCopy = valueCopy;
+ tree->size = 0;
+ return tree;
+}
+
+void
+parcTreeRedBlack_Destroy(PARCTreeRedBlack **treePointer)
+{
+ assertNotNull(treePointer, "pointer to pointer to tree can't be null");
+ assertNotNull(*treePointer, "pointer to tree can't be null");
+
+ if ((*treePointer)->size > 0) {
+ // If we have any elements in the tree, free them
+ _rbNodeFreeRecursive(*treePointer, (*treePointer)->root);
+ }
+
+ // Free the nil element
+ parcMemory_Deallocate((void **) &((*treePointer)->nil));
+
+ parcMemory_Deallocate((void **) treePointer);
+ *treePointer = NULL;
+}
+
+void
+parcTreeRedBlack_Insert(PARCTreeRedBlack *tree, void *key, void *value)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+ assertNotNull(value, "Value can't be NULL");
+
+ Node *newNode = _rbNodeCreate(tree, RED);
+ Node *parent = tree->nil;
+ Node *node;
+
+ // Set the value for the created node
+ newNode->key = key;
+ newNode->value = value;
+
+ // Start at the top
+ node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ parent = node;
+ if (_rbNodeIsEqual(tree, node, key)) {
+ // We're trying to insert the same value
+ _rbNodeUpdate(tree, node, newNode);
+ return;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ // The key is smaller
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+
+ // We're at the bottom.
+ // node is nil (a leaf)
+ newNode->parent = parent;
+ if (parent == tree->nil) {
+ // nil is our parent, we are the root
+ tree->root = newNode;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, parent, key)) {
+ parent->left_child = newNode;
+ } else {
+ parent->right_child = newNode;
+ }
+ }
+
+ // We have inserted one node.
+ tree->size++;
+
+ // We have a correct tree. But we need to regain the red-black property.
+ _rbNodeFix(tree, newNode);
+
+}
+
+// Return value
+void *
+parcTreeRedBlack_Get(PARCTreeRedBlack *tree, const void *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ Node *node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ // We found the node, return
+ return node->value;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+ return NULL;
+}
+
+// Return value, remove from tree
+void *
+parcTreeRedBlack_Remove(PARCTreeRedBlack *tree, const void *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+
+ Node *node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ _rbNodeRemove(tree, node);
+ void *value = node->value;
+ if (tree->keyFree != NULL) {
+ tree->keyFree(&node->key);
+ }
+ parcMemory_Deallocate((void **) &node);
+ return value;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+
+ // We didn't find the node
+
+ return NULL;
+}
+
+// remove from tree and destroy
+void
+parcTreeRedBlack_RemoveAndDestroy(PARCTreeRedBlack *tree, const void *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+
+ Node *node = tree->root;
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ _rbNodeRemove(tree, node);
+ _rbNodeFree(tree, node);
+ return;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+}
+
+void *
+parcTreeRedBlack_LastKey(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ Node *node = tree->root;
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ // Let's get to the bottom right of the tree to find the largest
+ while (node->right_child != tree->nil) {
+ node = node->right_child;
+ }
+
+ return node->key;
+}
+
+void *
+parcTreeRedBlack_FirstKey(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ Node *node = tree->root;
+
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ // Let's get to the bottom left of the tree to find the smallest
+ while (node->left_child != tree->nil) {
+ node = node->left_child;
+ }
+
+ return node->key;
+}
+
+size_t
+parcTreeRedBlack_Size(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ return tree->size;
+}
+
+static void
+_rbGetKeys(Node *node, void *data)
+{
+ PARCArrayList *list = (PARCArrayList *) data;
+ parcArrayList_Add(list, node->key);
+}
+
+PARCArrayList *
+parcTreeRedBlack_Keys(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ PARCArrayList *keys = parcArrayList_Create(NULL);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeRedBlack *) tree, tree->root, _rbGetKeys, keys);
+ }
+ return keys;
+}
+
+static void
+_rbGetValues(Node *node, void *data)
+{
+ PARCArrayList *list = (PARCArrayList *) data;
+ parcArrayList_Add(list, node->value);
+}
+
+PARCArrayList *
+parcTreeRedBlack_Values(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ PARCArrayList *values = parcArrayList_Create(NULL);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeRedBlack *) tree, tree->root, _rbGetValues, values);
+ }
+ return values;
+}
+
+int
+parcTreeRedBlack_Equals(const PARCTreeRedBlack *tree1, const PARCTreeRedBlack *tree2)
+{
+ assertNotNull(tree1, "Tree can't be NULL");
+ assertNotNull(tree2, "Tree can't be NULL");
+
+ int ret = 1;
+
+ PARCArrayList *keys1 = parcTreeRedBlack_Keys(tree1);
+ PARCArrayList *keys2 = parcTreeRedBlack_Keys(tree2);
+ size_t length1 = parcArrayList_Size(keys1);
+ size_t length2 = parcArrayList_Size(keys2);
+
+ if (length1 == length2) {
+ for (size_t i = 0; i < length1; i++) {
+ if (tree1->keyCompare(parcArrayList_Get(keys1, i), parcArrayList_Get(keys2, i)) != 0) {
+ ret = 0;
+ break;
+ }
+ }
+ if (ret != 0) {
+ PARCArrayList *values1 = parcTreeRedBlack_Values(tree1);
+ PARCArrayList *values2 = parcTreeRedBlack_Values(tree2);
+ size_t length1 = parcArrayList_Size(values1);
+ size_t length2 = parcArrayList_Size(values2);
+ if (length1 == length2) {
+ for (size_t i = 0; i < length1; i++) {
+ void *value1 = parcArrayList_Get(values1, i);
+ void *value2 = parcArrayList_Get(values2, i);
+ if (tree1->valueEquals != NULL) {
+ if (tree1->valueEquals(value1, value2) == 0) {
+ ret = 0;
+ break;
+ }
+ } else {
+ if (value1 != value2) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ }
+ parcArrayList_Destroy(&values1);
+ parcArrayList_Destroy(&values2);
+ }
+ } else {
+ ret = 0;
+ }
+
+ parcArrayList_Destroy(&keys1);
+ parcArrayList_Destroy(&keys2);
+ return ret;
+}
+
+
+/*
+ * This is a simple implementation of Copy that goes through the list of keys and values.
+ */
+PARCTreeRedBlack *
+parcTreeRedBlack_Copy(const PARCTreeRedBlack *source_tree)
+{
+ assertNotNull(source_tree, "Tree can't be NULL");
+
+ void *key_source;
+ void *key_copy;
+ void *value_source;
+ void *value_copy;
+
+ PARCTreeRedBlack *tree_copy = parcTreeRedBlack_Create(source_tree->keyCompare,
+ source_tree->keyFree,
+ source_tree->keyCopy,
+ source_tree->valueEquals,
+ source_tree->valueFree,
+ source_tree->valueCopy);
+
+ PARCArrayList *keys = parcTreeRedBlack_Keys(source_tree);
+ PARCArrayList *values = parcTreeRedBlack_Values(source_tree);
+
+ size_t total_keys = parcArrayList_Size(keys);
+
+ for (size_t i = 0; i < total_keys; i++) {
+ key_source = parcArrayList_Get(keys, i);
+ value_source = parcArrayList_Get(values, i);
+
+ if (source_tree->keyCopy != NULL) {
+ key_copy = source_tree->keyCopy(key_source);
+ } else {
+ key_copy = key_source;
+ }
+
+ if (source_tree->valueCopy != NULL) {
+ value_copy = source_tree->valueCopy(value_source);
+ } else {
+ value_copy = value_source;
+ }
+
+ parcTreeRedBlack_Insert(tree_copy, key_copy, value_copy);
+ }
+
+ parcArrayList_Destroy(&keys);
+ parcArrayList_Destroy(&values);
+
+ return tree_copy;
+}
diff --git a/libparc/parc/algol/parc_TreeRedBlack.h b/libparc/parc/algol/parc_TreeRedBlack.h
new file mode 100755
index 00000000..52d4af36
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeRedBlack.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_TreeRedBlack.h
+ * @ingroup datastructures
+ * @brief A red-black tree is a type of self-balancing binary search tree,
+ * a data structure used in computer science, typically used to implement associative arrays.
+ *
+ */
+#ifndef libparc_parc_TreeRedBlack_h
+#define libparc_parc_TreeRedBlack_h
+
+#include <stdlib.h>
+#include <parc/algol/parc_ArrayList.h>
+
+struct parc_tree_redblack;
+typedef struct parc_tree_redblack PARCTreeRedBlack;
+
+/**
+ * Compare two keys (signum)
+ *
+ * This is the definition of a function that takes two keys and compares them.
+ * It is a signum function. A user of the RedBlack tree will provide this function on creation
+ * so the tree can perform it's operations.
+ *
+ * @param [in] key1 The first key to compare
+ * @param [in] key2 The second key to compare
+ * @return A signum comparison. negative if key 1 is smaller, 0 if key1 == key2, greater than 0 if key1 is bigger.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef int (PARCTreeRedBlack_KeyCompare)(const void *key1, const void *key2);
+
+/**
+ * Compare two values for equality
+ *
+ * This is a function definiton for a function that compares two values in a `PARCTreeRedBlack`.
+ * If the values are equal it will return true. If they are not it will return false.
+ * A function of this type will be given on the creation of the `PARCTreeRedBlack`. It will be used by the tree
+ * to test equality.
+ *
+ * @param [in] value1 The first value to compare
+ * @param [in] value2 The second value to compare
+ * @return TRUE if the values are considered equal, FALSE if they are not
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef bool (PARCTreeRedBlack_ValueEquals)(const void *value1, const void *value2);
+
+/**
+ * A function to free a value pointer
+ *
+ * This is a function definition for a function to free a value in the `PARCTreeRedBlack`. The function should
+ * free/destroy the value when called. A function of this type will be passed to the `PARCTreeRedBlack` on
+ * creation. It will be used to destroy values when needed.
+ *
+ * @param [in,out] value A pointer to a pointer to a value to be freed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef void (PARCTreeRedBlack_ValueFree)(void **value);
+
+/**
+ * A function to free a key pointer
+ *
+ * This is a function definition for a function to free a key in the `PARCTreeRedBlack`. The function should
+ * free/destroy the key when called. A function of this type will be passed to the `PARCTreeRedBlack` on
+ * creation. It will be used to destroy keys when needed.
+ *
+ * @param [in,out] key A pointer to a pointer to a key to be freed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef void (PARCTreeRedBlack_KeyFree)(void **key);
+
+/**
+ * Create a copy of a key.
+ *
+ * This must be a real copy! (allocating new memory)
+ *
+ * This function should create a copy of the key. The copy must pass an equality test to the original key.
+ * If this function retuns NULL, the tree copy will fail (and return NULL)
+ *
+ * @param [in] key A pointer to the key to be copied
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new key instance
+ *
+ */
+typedef void * (PARCTreeRedBlack_KeyCopy)(const void *key);
+
+/**
+ * Create a copy of a value
+ *
+ * This must be a real copy! (new memory allocated)
+ *
+ * This function should create a copy of the value. The copy must pass an equality test to the original value.
+ * If this function retuns NULL, the tree copy will fail (and return NULL)
+ *
+ * @param [in] value A pointer to the value to be copied
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new value instance
+ *
+ */
+typedef void * (PARCTreeRedBlack_ValueCopy)(const void *value);
+
+/**
+ * Create a `PARCTreeRedBlack`
+ *
+ * Create a RedBlack Tree. You must provide a key compare function.
+ * The valueEquals function will be used to compare 2 trees. If you do not provide such a function
+ * the values will be compared directly.
+ * The keyFree and valueFree functions are optional but highly encouraged. They will be used on
+ * destruction of the tree on any remaining elements. They are also used on deletion of elements.
+ *
+ * @param [in] keyCompare A function to compare keys (required)
+ * @param [in] keyFree A function to free Keys (may be NULL)
+ * @param [in] keyCopy A function to copy Keys (may be NULL)
+ * @param [in] valueEquals A function to test value equality (may be NULL)
+ * @param [in] valueFree A function to free Values (may be NULL)
+ * @param [in] valueCopy A function to free Keys (may be NULL)
+ * @return NULL Error allocating memory
+ * @return Non-NULL An initialized RedBlack tree
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCTreeRedBlack *parcTreeRedBlack_Create(PARCTreeRedBlack_KeyCompare *keyCompare,
+ PARCTreeRedBlack_KeyFree *keyFree,
+ PARCTreeRedBlack_KeyCopy *keyCopy,
+ PARCTreeRedBlack_ValueEquals *valueEquals,
+ PARCTreeRedBlack_ValueFree *valueFree,
+ PARCTreeRedBlack_ValueCopy *valueCopy);
+
+/**
+ * Destroy a `PARCTreeRedBlack`
+ *
+ * Destroy a `PARCTreeRedBlack`, free all the memory.
+ * All remaining keys and values will be freed with the respective free functions.
+ *
+ * @param [in,out] treePointer A pointer to a pointer to the `PARCTreeRedBlack` to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcTreeRedBlack_Destroy(PARCTreeRedBlack **treePointer);
+
+/**
+ * Insert a value into the `PARCTreeRedBlack`.
+ *
+ * Insert a value into the `PARCTreeRedBlack`.
+ * If the key exists in the tree then the new value will replace the old value.
+ * The old key and value will be freed using the provided free functions.
+ * The tree will take ownership of the key and value. They can't be NULL.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key - This may not be NULL.
+ * @param [in] value A pointer to a value - This may not be NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcTreeRedBlack_Insert(PARCTreeRedBlack *tree, void *key, void *value);
+
+/**
+ * Get a value into the `PARCTreeRedBlack`.
+ *
+ * Get a value from a `PARCTreeRedBlack`.
+ * If the key is not found in the tree NULL is returned.
+ * The returned value will still be owned by the tree.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_Get(PARCTreeRedBlack *tree, const void *key);
+
+/**
+ * Get the first (smallest) key from a `PARCTreeRedBlack`.
+ *
+ * Get the first (smallest) key from a `PARCTreeRedBlack`.
+ * The returned key will still be owned by the tree.
+ * If the tree is empty the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @return A pointer to the smallest key. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_FirstKey(const PARCTreeRedBlack *tree);
+
+/**
+ * Get the last (largest) key from a `PARCTreeRedBlack`.
+ *
+ * Get the last (largest) key from a `PARCTreeRedBlack`.
+ * The returned key will still be owned by the tree.
+ * If the tree is empty the function will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @return A pointer to the smallest key. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_LastKey(const PARCTreeRedBlack *tree);
+
+/**
+ * Remove a value (and key) from a `PARCTreeRedBlack`.
+ *
+ * Remove a value from a `PARCTreeRedBlack`. The value (and key) will no longer be in the tree.
+ * The (internal) key will be freed. The provided key will not be modified.
+ * The value associated with the key will be returned. You will own this value.
+ * If the key is not found in the tree NULL is returned.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value. You will now own this value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_Remove(PARCTreeRedBlack *tree, const void *key);
+
+/**
+ * Remove and destroy a value (and key) from a `PARCTreeRedBlack`.
+ *
+ * Delete a value from a `PARCTreeRedBlack`. The value (and key) will no longer be in the tree.
+ * The value and key will be freed by the tree. The provided key will not be modified.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcTreeRedBlack_RemoveAndDestroy(PARCTreeRedBlack *tree, const void *key);
+
+/**
+ * Get the size of a `PARCTreeRedBlack`.
+ *
+ * Return the size of the tree (number of elements).
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @return size of the tree (number of elements).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcTreeRedBlack_Size(const PARCTreeRedBlack *tree);
+
+/**
+ * Get an ArrayList of the keys in this tree
+ *
+ * Get a list of the keys from this `PARCTreeRedBlack`. All of these keys will be valid keys in the `PARCTreeRedBlack`.
+ * The caller will own the list of keys and should destroy it when done. The caller will not own
+ * the keys themselves. Destroying the {@link PARCArrayList} should be enough.
+ * Note that if the tree is modified or destroyed the key pointers might no longer point to valid keys.
+ * The list of keys will be sorted (as defined by the key compare function, smallest first)
+ *
+ * @param [in] tree A pointer to a `PARCTreeRedBlack`.
+ * @return A list of (pointers to) keys.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcTreeRedBlack_Keys(const PARCTreeRedBlack *tree);
+
+/**
+ * Get an ArrayList of the values in this `PARCTreeRedBlack`.
+ *
+ * Get a list of the values from this tree. All of these values will be valid in the `PARCTreeRedBlack`.
+ * The caller will own the list of values and should destroy it when done. The caller will not own
+ * the values themselves. Destroying the {@link PARCArrayList} should be enough.
+ * Note that if the tree is modified or destroyed the value pointers might no longer point to valid values.
+ * The list of values will be sorted by key (as defined by the key compare function, smallest first).
+ *
+ * @param [in] tree A pointer to a `PARCTreeRedBlack`.
+ * @return A list of (pointers to) values.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcTreeRedBlack_Values(const PARCTreeRedBlack *tree);
+
+/**
+ * Calculate if two `PARCTreeRedBlack`s are equal
+ *
+ * Compare 2 `PARCTreeRedBlack` for equality.
+ * Two trees are equal if they have the same keys associated with the same values. The values
+ * will be compared using the valueEquals function provided on create. If this function was not
+ * provided it will compare the actual values.
+ *
+ * @param [in] tree1 A pointer to a `PARCTreeRedBlack`.
+ * @param [in] tree2 A pointer to another `PARCTreeRedBlack`.
+ * @return true if the trees are equal, zero otherwise
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcTreeRedBlack_Equals(const PARCTreeRedBlack *tree1, const PARCTreeRedBlack *tree2);
+
+/**
+ * Copy a RedBlack Tree
+ *
+ * Crete a copy of a RedBlack Tree.
+ * This will create a completely new tree. It will copy every key and every value using the Copy functions
+ * provided at tree creation. If these functions are NULL then the numeric values will be copied directly.
+ *
+ * @param [in] source_tree A pointer to a `PARCTreeRedBlack` to be copied
+ * @return NULL Error copying the tree.
+ * @return Non-NULL A copy of the `PARCTreeRedBlack`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeRedBlack * source_tree = parcTreeRedBlack_Create(.....);
+ *
+ * ... operations on tree ...
+ *
+ * PARCTreeRedBlack * tree_copy = parcTreeRedBlack_Copy(source_tree);
+ *
+ * ... operations on tree ...
+ *
+ * parcTreeRedBlack_Destroy(&source_tree);
+ * parcTreeRedBlack_Destroy(&tree_copy);
+ * }
+ * @endcode
+ */
+PARCTreeRedBlack *parcTreeRedBlack_Copy(const PARCTreeRedBlack *source_tree);
+#endif // libparc_parc_TreeRedBlack_h
diff --git a/libparc/parc/algol/parc_URI.c b/libparc/parc/algol/parc_URI.c
new file mode 100644
index 00000000..172468d8
--- /dev/null
+++ b/libparc/parc/algol/parc_URI.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include <parc/algol/parc_URIPath.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+char *sub_delims = "!$&'()*+,;=";
+char *gen_delims = ":/?#[]@";
+
+#define isSubDelims(c) (c != 0 && strchr(sub_delims, c) != NULL)
+#define isGenDelims(c) (c != 0 && strchr(gen_delims, c) != NULL)
+#define isDigit(c) (c >= '0' && c <= '9')
+#define isAlpha(c) (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+
+#define isUnreserved(c) (isAlpha(c) || isDigit(c) || c == '-' || c == '.' || c == '_' || c == '~')
+#define isReserved(c) (isGenDelims(c) || isSubDelims(c))
+#define isPchar(c) (isUnreserved(c) || isSubDelims(c) || c == ':' || c == '@')
+
+struct parc_uri {
+ char *scheme;
+ char *authority;
+ PARCURIPath *path;
+ char *query;
+ char *fragment;
+};
+
+static void
+_parcURI_Finalize(PARCURI **uriPtr)
+{
+ assertNotNull(uriPtr, "Parameter must be a non-null pointer to a pointer to a PARCURI instance.");
+
+ PARCURI *uri = *uriPtr;
+
+ if (uri->scheme != NULL) {
+ parcMemory_Deallocate((void **) &uri->scheme);
+ }
+
+ if (uri->authority != NULL) {
+ parcMemory_Deallocate((void **) &(uri->authority));
+ }
+
+ if (uri->path) {
+ parcURIPath_Release(&uri->path);
+ }
+
+ if (uri->query != NULL) {
+ parcMemory_Deallocate((void **) &(uri->query));
+ }
+
+ if (uri->fragment != NULL) {
+ parcMemory_Deallocate((void **) &(uri->fragment));
+ }
+}
+
+parcObject_ExtendPARCObject(PARCURI, _parcURI_Finalize, parcURI_Copy, parcURI_ToString, parcURI_Equals, NULL, NULL, NULL);
+
+PARCURI *
+parcURI_Create(void)
+{
+ PARCURI *result = parcObject_CreateAndClearInstance(PARCURI);
+ return result;
+}
+
+
+PARCURI *
+parcURI_CreateFromValist(const char *restrict format, va_list argList)
+{
+ PARCURI *result = NULL;
+
+ char *string;
+ if (vasprintf(&string, format, argList) != -1) {
+ result = parcURI_Parse(string);
+ free(string);
+ }
+ return result;
+}
+
+PARCURI *
+parcURI_CreateFromFormatString(const char *restrict format, ...)
+{
+ va_list argList;
+ va_start(argList, format);
+
+ PARCURI *result = parcURI_CreateFromValist(format, argList);
+
+ va_end(argList);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURI, PARCURI);
+
+parcObject_ImplementRelease(parcURI, PARCURI);
+
+static bool
+_parcURI_SchemeEquals(const char *schemeA, const char *schemeB)
+{
+ if (schemeA == schemeB) {
+ return true;
+ }
+ if (schemeA == NULL || schemeB == NULL) {
+ return false;
+ }
+ return strcmp(schemeA, schemeB) == 0;
+}
+
+static bool
+_parcURI_AuthorityEquals(const char *authorityA, const char *authorityB)
+{
+ if (authorityA == authorityB) {
+ return true;
+ }
+ if (authorityA == NULL || authorityB == NULL) {
+ return false;
+ }
+ return strcmp(authorityA, authorityB) == 0;
+}
+
+static bool
+_parcURI_QueryEquals(const char *queryA, const char *queryB)
+{
+ if (queryA == queryB) {
+ return true;
+ }
+ if (queryA == NULL || queryB == NULL) {
+ return false;
+ }
+ return strcmp(queryA, queryB) == 0;
+}
+
+static bool
+_parcURI_FragmentEquals(const char *fragmentA, const char *fragmentB)
+{
+ if (fragmentA == fragmentB) {
+ return true;
+ }
+ if (fragmentA == NULL || fragmentB == NULL) {
+ return false;
+ }
+ return strcmp(fragmentA, fragmentB) == 0;
+}
+
+bool
+parcURI_Equals(const PARCURI *uriA, const PARCURI *uriB)
+{
+ if (uriA == uriB) {
+ return true;
+ }
+ if (uriA == NULL || uriB == NULL) {
+ return false;
+ }
+
+ if (_parcURI_SchemeEquals(uriA->scheme, uriB->scheme)) {
+ if (_parcURI_AuthorityEquals(uriA->authority, uriB->authority)) {
+ if (parcURIPath_Equals(uriA->path, uriB->path)) {
+ if (_parcURI_QueryEquals(uriA->query, uriB->query)) {
+ if (_parcURI_FragmentEquals(uriA->fragment, uriB->fragment)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ * Parse and return a copy of the scheme portion of the URI.
+ *
+ * If this function returns successfully,
+ * the input parameter @p pointer will point to either a null-byte or the first character
+ * after the ':' separating the scheme from the rest of the URI.
+ *
+ * @return non-NULL An allocated string copy of the string which must be freed by the caller via <code>parcMemory_Deallocate</code>.
+ * @return NULL The scheme is malformed.
+ */
+static char *
+_parseScheme(const char *uri, const char **pointer)
+{
+ size_t length = 0;
+
+ const char *p = uri;
+ while (*p != 0 && *p != ':') {
+ length++;
+ p++;
+ }
+ if (*p == 0) {
+ return NULL;
+ }
+
+ if (length == 0) {
+ return NULL;
+ }
+
+ char *result = parcMemory_StringDuplicate(uri, length);
+
+ *pointer = (char *) &uri[length + 1];
+ return result;
+}
+
+/**
+ * @function _parseAuthority
+ * @abstract Parse the authority portion of a URI, if present.
+ * @discussion
+ * A URI may have an optional authority component.
+ * If the given string begins with a double forward slash ("//"),
+ * then it is followed by an authority part and a path.
+ * If the string doesn't begin with ("//") it contains only a path and this
+ * function simply returns NULL and setting the give pointer to the first
+ * character of the (expected) path.
+ *
+ * @param string A pointer to the start of the (potential) authority component.
+ * @param pointer A pointer to a character pointer that will be assigned point to the first character that begins the path.
+ * @return An allocated string, to be freed via parcMemory_Deallocate, if the authority portion is present or NULL if otherwise.
+ */
+static char *
+_parseAuthority(const char *string, const char **pointer)
+{
+ if (string[0] == '/' && string[1] == '/') {
+ size_t length = 0;
+ for (const char *p = &string[2]; *p != '/'; p++) {
+ if (*p == 0) {
+ *pointer = p;
+ break;
+ }
+ length++;
+ }
+
+ char *result = parcMemory_StringDuplicate(&string[2], length);
+ // The pointer must point to the first character *after* the '/' character as the '/' is not part of the path.
+ *pointer = &(&string[2])[length];
+ return result;
+ }
+ *pointer = string;
+ return NULL;
+}
+
+static char *
+_parseQuery(const char *string, const char **pointer)
+{
+ if (*string != '?') {
+ return NULL;
+ }
+
+ string++;
+ size_t length = 0;
+ for (const char *p = string; *p != 0 && *p != '#'; p++) {
+ length++;
+ }
+
+ char *result = parcMemory_StringDuplicate(string, length);
+ *pointer = &string[length];
+ return result;
+}
+
+static char *
+_parseFragment(const char *string, const char **pointer)
+{
+ if (*string != '#') {
+ return NULL;
+ }
+ string++;
+ size_t length = 0;
+ for (const char *p = string; *p != 0; p++) {
+ length++;
+ }
+ char *result = parcMemory_StringDuplicate(string, length);
+
+ *pointer = &string[length];
+ return result;
+}
+
+static void
+_parcURI_SetScheme(PARCURI *uri, const char *scheme)
+{
+ if (uri->scheme != NULL) {
+ parcMemory_Deallocate((void **) &(uri->scheme));
+ }
+ if (scheme == NULL) {
+ uri->scheme = NULL;
+ } else {
+ uri->scheme = parcMemory_StringDuplicate(scheme, strlen(scheme));
+ }
+}
+
+static void
+_parcURI_SetAuthority(PARCURI *uri, const char *authority)
+{
+ if (uri->authority != NULL) {
+ parcMemory_Deallocate((void **) &(uri->authority));
+ }
+ if (authority == NULL) {
+ uri->authority = NULL;
+ } else {
+ uri->authority = parcMemory_StringDuplicate(authority, strlen(authority));
+ }
+}
+
+static void
+_parcURI_SetQuery(PARCURI *uri, const char *query)
+{
+ if (uri->query != NULL) {
+ parcMemory_Deallocate((void **) &(uri->query));
+ }
+ if (query == NULL) {
+ uri->query = NULL;
+ } else {
+ uri->query = parcMemory_StringDuplicate(query, strlen(query));
+ }
+}
+
+static void
+_parcURI_SetFragment(PARCURI *uri, const char *fragment)
+{
+ if (uri->fragment != NULL) {
+ parcMemory_Deallocate((void **) &(uri->fragment));
+ }
+ if (fragment == NULL) {
+ uri->fragment = NULL;
+ } else {
+ uri->fragment = parcMemory_StringDuplicate(fragment, strlen(fragment));
+ }
+}
+
+PARCURI *
+parcURI_Parse(const char *string)
+{
+ const char *pointer = string;
+
+ PARCURI *result = parcURI_Create();
+
+ if (result != NULL) {
+ result->scheme = _parseScheme(pointer, &pointer);
+ if (result->scheme != NULL) {
+ result->authority = _parseAuthority(pointer, &pointer);
+ result->path = parcURIPath_Parse(pointer, &pointer);
+ result->query = _parseQuery(pointer, &pointer);
+ result->fragment = _parseFragment(pointer, &pointer);
+ } else {
+ parcURI_Release(&result);
+ result = NULL;
+ }
+ }
+
+ return result;
+}
+
+PARCURI *
+parcURI_Copy(const PARCURI *uri)
+{
+ PARCURI *result = parcURI_Create();
+
+ if (result != NULL) {
+ _parcURI_SetScheme(result, parcURI_GetScheme(uri));
+ _parcURI_SetAuthority(result, parcURI_GetAuthority(uri));
+ result->path = parcURIPath_Copy(parcURI_GetPath(uri));
+ _parcURI_SetQuery(result, parcURI_GetQuery(uri));
+ _parcURI_SetFragment(result, parcURI_GetFragment(uri));
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcURI_BuildString(const PARCURI *uri, PARCBufferComposer *composer)
+{
+ parcBufferComposer_PutStrings(composer, parcURI_GetScheme(uri), ":", NULL);
+
+ if (parcURI_GetAuthority(uri)) {
+ parcBufferComposer_PutString(composer, "//");
+ parcBufferComposer_PutString(composer, parcURI_GetAuthority(uri));
+ }
+
+ parcBufferComposer_PutString(composer, "/");
+ parcURIPath_BuildString(parcURI_GetPath(uri), composer);
+
+ if (parcURI_GetQuery(uri)) {
+ parcBufferComposer_PutStrings(composer, "?", parcURI_GetQuery(uri), NULL);
+ }
+
+ if (parcURI_GetFragment(uri)) {
+ parcBufferComposer_PutStrings(composer, "#", parcURI_GetFragment(uri), NULL);
+ }
+
+ return composer;
+}
+
+char *
+parcURI_ToString(const PARCURI *uri)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ if (parcURI_BuildString(uri, composer) != NULL) {
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+const char *
+parcURI_GetScheme(const PARCURI *uri)
+{
+ return uri->scheme;
+}
+
+const char *
+parcURI_GetAuthority(const PARCURI *uri)
+{
+ return uri->authority;
+}
+
+PARCURIPath *
+parcURI_GetPath(const PARCURI *uri)
+{
+ return uri->path;
+}
+
+const char *
+parcURI_GetQuery(const PARCURI *uri)
+{
+ return uri->query;
+}
+
+const char *
+parcURI_GetFragment(const PARCURI *uri)
+{
+ return uri->fragment;
+}
diff --git a/libparc/parc/algol/parc_URI.h b/libparc/parc/algol/parc_URI.h
new file mode 100644
index 00000000..7ac6be1f
--- /dev/null
+++ b/libparc/parc/algol/parc_URI.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_URI.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier
+ *
+ * An RF2396 compliant URI implementation with facilities for composition, decomposition,
+ * comparison, manipulation, etc.
+ *
+ */
+#ifndef libparc_parc_URI_h
+#define libparc_parc_URI_h
+
+#include <parc/algol/parc_URIPath.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+struct parc_uri;
+typedef struct parc_uri PARCURI;
+
+/**
+ * Create a new `PARCURI` object.
+ *
+ * The new `PARCURI` object is empty.
+ *
+ * @return A pointer to a `PARCURI` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *uri = parcURI_Create();
+ * ...
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_Create(void);
+
+/**
+ * Create a new instance of `PARCURI` from the given format string and arguments.
+ *
+ * @param [in] format A pointer to a nul-terminated printf format string
+ * @param [in] argList A pointer to a valid `va_list`
+ *
+ * @return non-NULL A pointer to a valid PARCURI instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *
+ * createFormatString(const char * restrict format, ...)
+ * {
+ * va_list argList;
+ * va_start(argList, format);
+ *
+ * PARCURI *uri = parcURI_CreateFromValist(format, argList);
+ *
+ * va_end(argList);
+ * return uri;
+ * }
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_CreateFromValist(const char *restrict format, va_list argList);
+
+/**
+ * Create a new instance of `PARCURI` from the given format string and variable number of parameters.
+ *
+ * @param [in] format A pointer to a nul-terminated printf format string
+ * @param [in] ... A variable number of parameters.
+ *
+ * @return non-NULL A pointer to a valid PARCURI instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *uri = parcURI_CreateFromFormatString("http://%s/index.html", "127.0.0.1");
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_CreateFromFormatString(const char *restrict format, ...);
+
+/**
+ * Increase the number of references to a `PARCURI` instance.
+ *
+ * Note that new `PARCURI` is not created,
+ * only that the given `PARCURI` reference count is incremented.
+ * Discard the reference by invoking {@link parcURI_Release}.
+ *
+ * @param uri A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *x = parcURI_Create();
+ *
+ * PARCURI *x2 = parcURI_Acquire(x);
+ *
+ * parcURI_Release(&x);
+ * parcURI_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcURI_Release
+ */
+PARCURI *parcURI_Acquire(const PARCURI *uri);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] uriPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *x = parcURI_Create();
+ *
+ * parcURI_Release(&x);
+ * }
+ * @endcode
+ */
+void parcURI_Release(PARCURI **uriPtr);
+
+/**
+ * Parse a well-formed URI into a `PARCURI` instance.
+ *
+ * The URI string must be null-terminated so that parsing can detect the
+ * end of the path correctly.
+ *
+ * @param [in] string The URI C-string used to create the `PARCURI` instance.
+ *
+ * @return non-NULL A pointer to an allocated `PARCURI` structure which must be destroyed via {@link parcURI_Release()}.
+ * @return NULL The URI was malformed.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ *
+ * PARCURI *uri = parcURI_Parse(uriString);
+ * if (uri == NULL) {
+ * printf("Malformed URI '%s', uriString);
+ * }
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_Parse(const char *string);
+
+/**
+ * Create a deep copy of the given `PARCURI` instance.
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return A deep copy of the given `PARCURI` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI *copy = parcURI_Copy(uri);
+ * // uri and copy will contain equivalent paths
+ *
+ * parcURI_Release(&uri);
+ * parcURI_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_Copy(const PARCURI *uri);
+
+/**
+ * Return true if two `PARCURI` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCURI` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] uriA The first `PARCURI` instance.
+ * @param [in] uriB The second `PARCURI` instance.
+ *
+ * @return true the given `PARCURI` instances are equal.
+ * @return false the given `PARCURI` instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ * PARCURI *copy = parcURI_Copy(uri);
+ *
+ * if (parcURI_Equals(uri, copy)) {
+ * printf("Paths are equal.\n");
+ * } else {
+ * printf("Paths are NOT equal.\n");
+ * }
+ *
+ * parcURI_Release(&uri);
+ * parcURI_Release(&copy);
+ * }
+ * @endcode
+ */
+bool parcURI_Equals(const PARCURI *uriA, const PARCURI *uriB);
+
+/**
+ * Get the scheme part of the given URI.
+ *
+ * The scheme of a URI path is the "type", e.g., labeled content
+ * identifier "lci" for "lci:/foo/bar".
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The scheme of the given `PARCURI` instance
+ * @return NULL If no scheme is available.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *scheme = parcURI_GetScheme(uri); // will be "lci"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetScheme(const PARCURI *uri);
+
+/**
+ * Get the authority part of the given `PARCURI`.
+ *
+ * The authority part of a URI is the string: username at host:port
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The authority of the given `PARCURI` instance
+ * @return NULL If no scheme is available.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *authority = parcURI_GetAuthority(uri); // will be "chris@parc.com:80"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetAuthority(const PARCURI *uri);
+
+/**
+ * Get the {@link PARCURIPath} part of the given URI.
+ *
+ * Every `PARCURI` contains a `PARCURIPath` consisting of the path portion of the URI.
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return The `PARCURIPath` part of the given URI.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com/foo/bar/";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *path = parcURI_GetPath(uri); // will be "/foo/bar/"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURI_GetPath(const PARCURI *uri);
+
+/**
+ * Get the query part of the given PARCURI`.
+ *
+ * Queries are contiguous key-value string segments of a URI.
+ * For example, the query of URI string "http://parc.com/x=1&y=2&z=3" is "x=1&y=2&z=3"
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The query string, if present, for the given URI
+ * @return NULL If no query string is present
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com/x=1&y=2&z=3";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *path = parcURI_GetQuery(uri); // will be "x=1&y=2&z=3"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetQuery(const PARCURI *uri);
+
+/**
+ * Get the fragment part of the given `PARCURI`.
+ *
+ * The fragment of a URI is the string component following the '#' character.
+ * For example, the fragment of URI string "http://parc.com/index.html#info" is "info"
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The fragment of the URI, if present
+ * @return NULL If no fragment is in the URI
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com/index.html#info";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *path = parcURI_GetFragment(uri); // will be "info"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetFragment(const PARCURI *uri);
+
+/**
+ * Append a representation of the specified `PARCURI` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] uri A pointer to a `PARCURI` instance whose representation should be appended to the @p composer.
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance to be modified.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcURI_BuildString(instance, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcURI_BuildString(const PARCURI *uri, PARCBufferComposer *composer);
+
+/**
+ * Produce an allocated null-terminated string representation of the given URI.
+ *
+ * The returned value must be destroyed via `parcMemory_Deallocate`
+ *
+ * @param [in] uri The `PARCURI` instance to format.
+ *
+ * @return An allocated null-terminated string representation of the given URI.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * printf("path string = %s\n", parcURI_ToString(uri));
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+char *parcURI_ToString(const PARCURI *uri);
+#endif // libparc_parc_URI_h
diff --git a/libparc/parc/algol/parc_URIAuthority.c b/libparc/parc/algol/parc_URIAuthority.c
new file mode 100644
index 00000000..ac2ee351
--- /dev/null
+++ b/libparc/parc/algol/parc_URIAuthority.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URIAuthority.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+struct parc_uri_authority {
+ char *userinfo;
+ char *hostName;
+ long port;
+};
+
+static void
+_parcURIAuthority_Finalize(PARCURIAuthority **authorityPtr)
+{
+ PARCURIAuthority *authority = *authorityPtr;
+ parcMemory_SafeFree(authority->userinfo);
+ parcMemory_SafeFree(authority->hostName);
+}
+
+parcObject_ExtendPARCObject(PARCURIAuthority, _parcURIAuthority_Finalize, NULL, NULL, parcURIAuthority_Equals, NULL, NULL, NULL);
+
+PARCURIAuthority *
+parcURIAuthority_Create(void)
+{
+ PARCURIAuthority *result = parcObject_CreateInstance(PARCURIAuthority);
+ result->userinfo = 0;
+ result->hostName = 0;
+ result->port = 0;
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURIAuthority, PARCURIAuthority);
+
+parcObject_ImplementRelease(parcURIAuthority, PARCURIAuthority);
+
+PARCURIAuthority *
+parcURIAuthority_Parse(const char *authority)
+{
+ PARCURIAuthority *result = parcURIAuthority_Create();
+
+ char *atSign = strchr(authority, '@');
+ if (atSign != NULL) {
+ result->userinfo = parcMemory_StringDuplicate(authority, atSign - authority);
+ authority = ++atSign;
+ }
+ // Support literal IPv6 address specifications (i.e. [::0]:80)
+ char *rightBracket = strrchr(authority, ']');
+ char *lastColon = strrchr(authority, ':');
+ if (rightBracket != NULL) {
+ result->hostName = parcMemory_StringDuplicate(authority, rightBracket - authority + 1);
+ if ((lastColon - rightBracket) > 0) {
+ result->port = (short) strtol(++lastColon, NULL, 10);
+ }
+ } else if (lastColon != NULL) {
+ result->hostName = parcMemory_StringDuplicate(authority, lastColon - authority);
+ result->port = (short) strtol(++lastColon, NULL, 10);
+ } else {
+ result->hostName = parcMemory_StringDuplicate(authority, strlen(authority));
+ }
+
+ return result;
+}
+
+const char *
+parcURIAuthority_GetUserInfo(const PARCURIAuthority *authority)
+{
+ return authority->userinfo;
+}
+
+const char *
+parcURIAuthority_GetHostName(const PARCURIAuthority *authority)
+{
+ return authority->hostName;
+}
+
+long
+parcURIAuthority_GetPort(const PARCURIAuthority *authority)
+{
+ return authority->port;
+}
+
+bool
+parcURIAuthority_Equals(const PARCURIAuthority *authA, const PARCURIAuthority *authB)
+{
+ if (authA == authB) {
+ return true;
+ }
+ if (authA == NULL || authB == NULL) {
+ return false;
+ }
+
+ if (strcmp(authA->hostName, authB->hostName) == 0) {
+ if (strcmp(authA->userinfo, authB->userinfo) == 0) {
+ if (authA->port == authB->port) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+ }
+
+ return false;
+}
diff --git a/libparc/parc/algol/parc_URIAuthority.h b/libparc/parc/algol/parc_URIAuthority.h
new file mode 100644
index 00000000..49d19734
--- /dev/null
+++ b/libparc/parc/algol/parc_URIAuthority.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_URIAuthority.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier (URI) Authority
+ *
+ */
+#ifndef libparc_parc_URIAuthority_h
+#define libparc_parc_URIAuthority_h
+
+#include <stdbool.h>
+
+struct parc_uri_authority;
+typedef struct parc_uri_authority PARCURIAuthority;
+
+/**
+ * Create a new `PARCURIAuthority` object.
+ *
+ * The new `PARCURIAuthority` object is empty.
+ *
+ * @return A pointer to a `PARCURIAuthority` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIAuthority *auth = parcURIAuthority_Create();
+ * ...
+ * parcURIAuthority_Release(&auth);
+ * }
+ * @endcode
+ */
+PARCURIAuthority *parcURIAuthority_Create(void);
+
+/**
+ * Increase the number of references to a `PARCURIAuthority` instance.
+ *
+ * Note that new `PARCURIAuthority` is not created,
+ * only that the given `PARCURIAuthority` reference count is incremented.
+ * Discard the reference by invoking `parcURIAuthority_Release`.
+ *
+ * @param auth A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIAuthority *x = parcURIAuthority_Create();
+ *
+ * PARCURIAuthority *x2 = parcURIAuthority_Acquire(x);
+ *
+ * parcURIAuthority_Release(&x);
+ * parcURIAuthority_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcURIAuthority_Release
+ */
+PARCURIAuthority *parcURIAuthority_Acquire(const PARCURIAuthority *auth);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] authPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIAuthority *auth = parcURIAuthority_Create();
+ *
+ * parcURIAuthority_Release(&auth);
+ * }
+ * @endcode
+ */
+void parcURIAuthority_Release(PARCURIAuthority **authPtr);
+
+/**
+ * Return true if two `PARCURIAuthority` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCURIAuthority` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, parcURIAuthority_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcURIAuthority_Equals(x, y) must return true if and only if
+ * parcURIAuthority_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcURIAuthority_Equals(x, y) returns true and
+ * parcURIAuthority_Equals(y, z) returns true,
+ * then parcURIAuthority_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcURIAuthority_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcURIAuthority_Equals(x, NULL)) must return false.
+ *
+ * @param [in] authA The first `PARCURIAuthority` instance.
+ * @param [in] authB The second `PARCURIAuthority` instance.
+ *
+ * @return true the given `PARCURIAuthority` instances are equal.
+ * @return false the given `PARCURIAuthority` instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * PARCURI_Authority *handle = parcURIAuthority_Acquire(authority);
+ *
+ * if (parcURIAuthority_Equals(authority, handle)) {
+ * printf("Authorities are equal.\n");
+ * } else {
+ * printf("Authorities are NOT equal.\n");
+ * }
+ *
+ * parcURIAuthority_Release(&uri);
+ * parcURIAuthority_Release(&copy);
+ * }
+ * @endcode
+ */
+bool parcURIAuthority_Equals(const PARCURIAuthority *authA, const PARCURIAuthority *authB);
+
+/**
+ * Produce a `PARCURI_Authority` type from the authority string.
+ *
+ * The returned value must be destroyed via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] authority The authority string to parse.
+ *
+ * @return A newly allocated `PARCURI_Authority` string.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * // use the authority
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+PARCURIAuthority *parcURIAuthority_Parse(const char *authority);
+
+/**
+ * Retrieve the user information from the given `PARCURI_Authority` instance.
+ *
+ * @param [in] authority The `PARCURI_Authority` instance being queried.
+ *
+ * @return The user info string component of the `PARCURI_Authority` instance. Copy the string prior to modification.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * printf("User info: "%s\n", parcURIAuthority_GetUserInfo(authority));
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURIAuthority_GetUserInfo(const PARCURIAuthority *authority);
+
+/**
+ * Retrieve the host name from the given `PARCURI_Authority` instance.
+ *
+ * @param [in] authority The `PARCURI_Authority` instance being queried.
+ *
+ * @return The host name string component of the `PARCURI_Authority` instance. Copy the string prior to modification.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * printf("Host name: "%s\n", parcURIAuthority_GetHostName(authority));
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURIAuthority_GetHostName(const PARCURIAuthority *authority);
+
+/**
+ * Retrieve the host port from the given `PARCURI_Authority` instance.
+ *
+ * @param [in] authority The `PARCURI_Authority` instance being queried.
+ *
+ * @return The host port string component of the `PARCURI_Authority` instance. Copy the string prior to modification.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * printf("Host port: "%s\n", parcURIAuthority_GetPort(authority));
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+long parcURIAuthority_GetPort(const PARCURIAuthority *authority);
+#endif /* defined(libparc_parc_URIAuthority_h) */
diff --git a/libparc/parc/algol/parc_URIPath.c b/libparc/parc/algol/parc_URIPath.c
new file mode 100755
index 00000000..ef46dac9
--- /dev/null
+++ b/libparc/parc/algol/parc_URIPath.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URIPath.h>
+
+#include <parc/algol/parc_URISegment.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_uri_path {
+ PARCArrayList *segments;
+};
+
+static void
+_parcURIPath_Finalize(PARCURIPath **pathPtr)
+{
+ assertNotNull(pathPtr, "Parameter must be a non-null pointer to a pointer to a PARCURIPath instance.");
+
+ PARCURIPath *path = *pathPtr;
+ if (path != NULL) {
+ parcArrayList_Destroy(&path->segments);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCURIPath, _parcURIPath_Finalize, parcURIPath_Copy, parcURIPath_ToString, parcURIPath_Equals,
+ parcURIPath_Compare, NULL, NULL);
+
+PARCURIPath *
+parcURIPath_Create(void)
+{
+ PARCURIPath *result = parcObject_CreateInstance(PARCURIPath);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURIPath, PARCURIPath);
+
+parcObject_ImplementRelease(parcURIPath, PARCURIPath);
+
+PARCURIPath *
+parcURIPath_Append(PARCURIPath *path, const PARCURISegment *segment)
+{
+ parcArrayList_Add(path->segments, segment);
+ return path;
+}
+
+PARCURIPath *
+parcURIPath_Trim(PARCURIPath *path, size_t numberToRemove)
+{
+ size_t length = parcArrayList_Size(path->segments);
+ if (numberToRemove <= length) {
+ while (numberToRemove--) {
+ parcArrayList_RemoveAndDestroyAtIndex(path->segments, length - 1);
+ length--;
+ }
+ }
+ return path;
+}
+
+//PARCURIPath *
+//parcURIPath_Parse(const char *string, const char **pointer)
+//{
+// PARCURIPath *result = parcURIPath_Create();
+//
+// result->segments = parcArrayList_Create((void (*)(void **))parcURISegment_Release);
+// if (*string != 0) {
+// assertTrue(*string == '/', "Expected initial '/' character.");
+// *pointer = string;
+// while (**pointer != 0 && **pointer != '?' && **pointer != '#') {
+// PARCURISegment *segment = parcURISegment_Parse(++(*pointer), pointer);
+// parcURIPath_Append(result, segment);
+// }
+// }
+//
+// return result;
+//}
+
+PARCURIPath *
+parcURIPath_Parse(const char *string, const char **pointer)
+{
+ PARCURIPath *result = parcURIPath_Create();
+ result->segments = parcArrayList_Create((void (*)(void **))parcURISegment_Release);
+
+ if (*string != 0) {
+ if (*string != '/') {
+ parcURIPath_Release(&result);
+ return NULL;
+ }
+
+ *pointer = string;
+ while (**pointer != 0 && **pointer != '?' && **pointer != '#') {
+ PARCURISegment *segment = parcURISegment_Parse(++(*pointer), pointer);
+ parcURIPath_Append(result, segment);
+ }
+ }
+
+ return result;
+}
+
+bool
+parcURIPath_Equals(const PARCURIPath *pathA, const PARCURIPath *pathB)
+{
+ if (pathA == pathB) {
+ return true;
+ }
+ if (pathA == NULL || pathB == NULL) {
+ return false;
+ }
+
+ if (parcArrayList_Size(pathA->segments) == parcArrayList_Size(pathB->segments)) {
+ for (size_t i = 0; i < parcArrayList_Size(pathA->segments); i++) {
+ PARCURISegment *segmentA = parcArrayList_Get(pathA->segments, i);
+ PARCURISegment *segmentB = parcArrayList_Get(pathB->segments, i);
+ if (!parcURISegment_Equals(segmentA, segmentB)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+PARCURIPath *
+parcURIPath_Copy(const PARCURIPath *path)
+{
+ assertNotNull(path, "Parameter must be a non-null PARC_URIPath pointer.");
+
+ PARCURIPath *result = parcURIPath_Create();
+ result->segments = parcArrayList_Create((void (*)(void **))parcURISegment_Release);
+
+ size_t nSegments = parcURIPath_Count(path);
+
+ for (size_t i = 0; i < nSegments; i++) {
+ PARCURISegment *segment = parcURIPath_Get(path, i);
+ PARCURISegment *segmentCopy = parcURISegment_Clone(segment);
+ parcURIPath_Append(result, segmentCopy);
+ }
+
+ return result;
+}
+
+PARCURIPath *
+parcURIPath_ComposeValist(const PARCURIPath *basePath, va_list varargs)
+{
+ PARCURIPath *result = parcURIPath_Copy(basePath);
+
+ for (PARCURISegment *segment = va_arg(varargs, PARCURISegment *); segment != NULL; segment = va_arg(varargs, PARCURISegment *)) {
+ parcURIPath_Append(result, parcURISegment_Clone(segment));
+ }
+
+ return result;
+}
+
+PARCURIPath *
+parcURIPath_Compose(const PARCURIPath *basePath, ...)
+{
+ va_list arglist;
+ va_start(arglist, basePath);
+
+ PARCURIPath *result = parcURIPath_ComposeValist(basePath, arglist);
+ va_end(arglist);
+
+ return result;
+}
+
+bool
+parcURIPath_StartsWith(const PARCURIPath *base, const PARCURIPath *prefix)
+{
+ size_t prefixSegmentCount = parcURIPath_Count(prefix);
+ size_t baseSegmentCount = parcURIPath_Count(base);
+
+ if (baseSegmentCount < prefixSegmentCount) {
+ return false;
+ }
+
+ for (size_t i = 0; i < prefixSegmentCount; i++) {
+ PARCURISegment *baseSegment = parcURIPath_Get(base, i);
+ PARCURISegment *prefixSegment = parcURIPath_Get(prefix, i);
+ if (parcURISegment_Compare(baseSegment, prefixSegment) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int
+parcURIPath_Compare(const PARCURIPath *pathA, const PARCURIPath *pathB)
+{
+ if (pathA == NULL) {
+ if (pathB == NULL) {
+ return 0;
+ }
+ return -1;
+ } else {
+ if (pathB == NULL) {
+ return +1;
+ }
+ }
+
+ ssize_t countDifference = parcURIPath_Count(pathA) - parcURIPath_Count(pathB);
+
+ if (countDifference != 0) {
+ return (countDifference > 0 ? 1 : (countDifference < 0) ? -1 : 0);
+ }
+
+ size_t nSegments = parcURIPath_Count(pathA);
+
+ for (size_t i = 0; i < nSegments; i++) {
+ PARCURISegment *segmentA = parcURIPath_Get(pathA, i);
+ PARCURISegment *segmentB = parcURIPath_Get(pathB, i);
+ int comparison = parcURISegment_Compare(segmentA, segmentB);
+ if (comparison != 0) {
+ return comparison;
+ }
+ }
+ return 0;
+}
+
+PARCURISegment *
+parcURIPath_Get(const PARCURIPath *path, size_t index)
+{
+ return (PARCURISegment *) parcArrayList_Get(path->segments, index);
+}
+
+size_t
+parcURIPath_Count(const PARCURIPath *path)
+{
+ size_t nSegments = parcArrayList_Size(path->segments);
+ return nSegments;
+}
+
+size_t
+parcURIPath_Length(const PARCURIPath *path)
+{
+ size_t result = 0;
+
+ size_t nSegments = parcURIPath_Count(path);
+
+ for (size_t i = 0; i < nSegments; i++) {
+ PARCURISegment *segment = parcURIPath_Get(path, i);
+ result += parcURISegment_Length(segment);
+ if (i < (nSegments - 1)) {
+ result++; // Include the size of the '/' separators.
+ }
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcURIPath_BuildString(const PARCURIPath *path, PARCBufferComposer *composer)
+{
+ size_t nSegments = parcArrayList_Size(path->segments);
+
+ for (size_t i = 0; i < nSegments && composer != NULL; i++) {
+ if (parcURISegment_BuildString(parcURIPath_Get(path, i), composer) == NULL) {
+ composer = NULL;
+ }
+ if (i < (nSegments - 1)) {
+ composer = parcBufferComposer_PutChar(composer, '/');
+ }
+ }
+
+ return composer;
+}
+
+char *
+parcURIPath_ToString(const PARCURIPath *path)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ if (parcURIPath_BuildString(path, composer) != NULL) {
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_URIPath.h b/libparc/parc/algol/parc_URIPath.h
new file mode 100755
index 00000000..d43d8651
--- /dev/null
+++ b/libparc/parc/algol/parc_URIPath.h
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_URIPath.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier (URI) Path
+ *
+ */
+#ifndef libparc_PARCURIPath_h
+#define libparc_PARCURIPath_h
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URISegment.h>
+
+struct parc_uri_path;
+typedef struct parc_uri_path PARCURIPath;
+
+/**
+ * Create a new `PARCURIPath` object.
+ *
+ * The new `PARCURIPath` object is empty.
+ *
+ * @return A pointer to a `PARCURIPath` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIPath *path = parcURIPath_Create();
+ * ...
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Create(void);
+
+/**
+ * Increase the number of references to a `PARCURIPath` instance.
+ *
+ * Note that new `PARCURIPath` is not created,
+ * only that the given `PARCURIPath` reference count is incremented.
+ * Discard the reference by invoking {@link parcURIPath_Release}.
+ *
+ * @param auth A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIPath *x = parcURIPath_Create();
+ *
+ * PARCURIPath *x2 = parcURIPath_Acquire(x);
+ *
+ * parcURIPath_Release(&x);
+ * parcURIPath_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcURIPath_Release
+ */
+PARCURIPath *parcURIPath_Acquire(const PARCURIPath *auth);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] pathPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIPath *path = parcURIPath_Create();
+ *
+ * parcURIPath_Release(&auth);
+ * }
+ * @endcode
+ */
+void parcURIPath_Release(PARCURIPath **pathPtr);
+
+/**
+ * Parse a complete URI path composed of URI segments.
+ *
+ * The parsed path is expected to conform to the syntax of '/' segment ['/' segment]
+ * terminated by either a null, '?', or '#' character.
+ *
+ * @param [in] string A pointer to character array containing the first '/' of the path.
+ * @param [in] pointer A pointer to character pointer that will point to the first character that is not the path.
+ *
+ * @return A newly allocated `PARCURIPath` instance that must be freed via {@link parcURIPath_Release()}
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/bar/, &pointer);
+ * // use the complete URI path
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Parse(const char *string, const char **pointer);
+
+/**
+ * Compares two `PARCURIPath` instances for order.
+ *
+ * As strings, URI paths are compared in normal lexographical order. This
+ * is analogous to strcmp(...).
+ *
+ * @param [in] pathA A `PARCURIPath` pointer, or NULL.
+ * @param [in] pathB A `PARCURIPath` pointer, or NULL.
+ *
+ * @return A negative integer, zero, or a positive integer as a is less than, equal to, or greater than b, accordingly.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *pathA = parcURIPath_Parse("lci:/foo/bar/, &pointer);
+ * PARCURIPath *pathB = parcURIPath_Parse("lci:/foo/bar/, &pointer);
+ * int cmp = parcURIPath_Compare(pathA, pathB);
+ * // cmp will be zero since both paths are the same
+ * }
+ * @endcode
+ */
+int parcURIPath_Compare(const PARCURIPath *pathA, const PARCURIPath *pathB);
+
+/**
+ * Create a new `PARCURIPath` comprised of a basePath concatenated with zero or more `PARCURISegment` instances.
+ *
+ * Create a new `PARCURIPath` instance comprised of the given `PARCURIPath`
+ * concatenated with the null terminated list of {@link PARCURISegment} instances.
+ *
+ * @param [in] basePath The base prefix path used to compose a new path
+ * @param [in] ... Any additional `PARCURISegment` instances that will be appended to the URI path.
+ *
+ * @return A newly allocated `PARCURIPath` instance
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *basePath = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURISegment *segment = parcURISegment_Create(3, "bar");
+ * PARCURIPath *path = parcURIPath_Compose(basePath, segment);
+ *
+ * // use the new composed path as needed
+ *
+ * parcURIPath_Release(&path);
+ * parcURIPath_Release(&basePath);
+ * parcURISegment_Destroy(&segment);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Compose(const PARCURIPath *basePath, ...);
+
+/**
+ * Create a new `PARCURIPath` comprised of a basePath concatenated with the number of given `PARCURISegment`
+ * instances provided by @p varargs.
+ *
+ * The variable number of `PARCURISegment` instances is signaled by the value `NULL` as the last element in @p varargs.
+ *
+ * @param [in] basePath The base prefix path used to compose a new path
+ * @param [in] varargs A valid va_list.
+ *
+ * @return A newly allocated `PARCURIPath` instance
+ *
+ * Example:
+ * @code
+ * PARCURIPath *
+ * myFunction(const PARCURIPath *basePath, ...)
+ * {
+ * va_list arglist;
+ * va_start(arglist, basePath);
+ *
+ * PARCURIPath *result = parcURIPath_ComposeValist(basePath, arglist);
+ * va_end(arglist);
+ *
+ * return result;
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_ComposeValist(const PARCURIPath *basePath, va_list varargs);
+
+/**
+ * Concatenate two paths together to form a single path.
+ *
+ * Concatenating "/a/b/" and "/c/d" URI paths will yield: "/a/b/c/d/".
+ *
+ * @param [in] pathA Pointer to the first path (prefix)
+ * @param [in] pathB Pointer to the second path (suffix)
+ *
+ * @return A `PARCURIPath` instance containing the concatenation of pathA and pathB, must be freed via {@link parcURIPath_Release()}
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *prefix = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURIPath *suffix = parcURIPath_Parse("/bar/", &pointer);
+ * PARCURIPath *concat = parcURIPath_Concat(prefix, suffix);
+ *
+ * // use the new path as needed
+ *
+ * parcURIPath_Release(&prefix);
+ * parcURIPath_Release(&suffix);
+ * parcURIPath_Release(&concat);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Concat(PARCURIPath *pathA, PARCURIPath *pathB);
+
+/**
+ * Determine if two `PARCURIPath` instances are equal.
+ *
+ * This function implements the following equivalence relations on non-null `PARCURIPath` instances:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcURIPath_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcURIPath_Equals(x, y)` must return true if and only if
+ * `parcURIPath_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcURIPath_Equals(x, y)` returns true and
+ * `parcURIPath_Equals(y, z)` returns true,
+ * then `parcURIPath_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcURIPath_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcURIPath_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] pathA First instance
+ * @param [in] pathB Second instance
+ *
+ * @return true Equal `PARCURIPath` instances
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *pathA = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURIPath *pathB = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * if (parcURIPath_Equals(pathA, pathB) {
+ * printf("Paths are equal\n");
+ * }
+ *
+ * parcURIPath_Release(&pathA);
+ * parcURIPath_Release(&pathB);
+ * }
+ * @endcode
+ */
+bool parcURIPath_Equals(const PARCURIPath *pathA, const PARCURIPath *pathB);
+
+/**
+ * Create a copy of the given `PARCURIPath`.
+ *
+ * This is a deep copy of the instance.
+ *
+ * @param [in] path The path to copy.
+ *
+ * @return A copy of the given `PARCURIPath`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURIPath *copy = parcURIPath_Copy(path);
+ *
+ * // use the copy as needed
+ *
+ * parcURIPath_Release(&path);
+ * parcURIPath_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Copy(const PARCURIPath *path);
+
+/**
+ * Append a path segment to an existing URI path.
+ *
+ * Appending "bar" to "lci:/foo" will yield "lci:/foo/bar".
+ * This modifies the URI path instance in place - it does not allocate
+ * a new instance.
+ *
+ * @param [in,out] path The `PARCURIPath` instance to which the segment is appended
+ * @param [in] segment The {@link PARCURISegment} to append to the path
+ *
+ * @return The modified `PARCURIPath` instance (equal to the first parameter).
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURISegment *segment = parcURISegment_Create(3, "bar");
+ * path = parcURIPath_Append(path, segment);
+ *
+ * // use the full path as necessary
+ *
+ * parcURIPath_Release(&path);
+ * parcURISegment_Destroy(&segment);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Append(PARCURIPath *path, const PARCURISegment *segment);
+
+/**
+ * Retrieve the URI path segment at the specified index.
+ *
+ * The index must be within the range [0, number of segments]
+ * prior to invocation. Otherwise, the program is terminated with LongBow trapOutOfBounds.
+ *
+ * @param [in] path A `PARCURIPath` instance to be examined.
+ * @param [in] index The index of the URI segment to retrieve.
+ *
+ * @return The {@link PARCURISegment} instance at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURISegment *segment = parcURIPath_Get(path, 0);
+ * // segment will be equal to "lci:"
+ *
+ * ...
+ *
+ * parcURIPath_Release(&path);
+ * parcURISegment_Destroy(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURIPath_Get(const PARCURIPath *path, size_t index);
+
+/**
+ * Return the number of segments in the given Path.
+ *
+ * @param [in] path The `PARCURIPath` instance to be examined.
+ *
+ * @return The integer length of the path, in segments.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * size_t numSegments = parcURIPath_Count(path);
+ * ...
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+size_t parcURIPath_Count(const PARCURIPath *path);
+
+/**
+ * Produce a null-terminated C-string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] path A pointer to the instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A null-terminated string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * char *stringRep = parcURIPath_ToString(path);
+ * printf("Path: %s\n", stringRep);
+ *
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+char *parcURIPath_ToString(const PARCURIPath *path);
+
+/**
+ * Remove N trailing segments from the given Path.
+ *
+ * @param [in,out] path The `PARCURIPath` instance being modified.
+ * @param [in] numberToRemove The number of segments to remove from the end.
+ *
+ * @return `PARCURIPath` The given `PARCURIPath` that has been modified in place
+ * @return NULL If @p numberToRemove is too large.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * ...
+ * path = parcURIPath_Trim(path, 1); // leaves "lci:/"
+ * ...
+ *
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Trim(PARCURIPath *path, size_t numberToRemove);
+
+/**
+ * Build a string representation of the `PARCURIPath` stored in a {@link PARCBufferComposer} instance.
+ *
+ * @param [in] path The `PARCURIPath` instance from which the string representation is made.
+ * @param [in,out] composer The `PARCBufferComposer` which is modified in place with the string representation.
+ *
+ * @return `PARCBufferComposer` The modified `PARCBufferComposer` that was passed in.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("/foo/bar/, &pointer);
+ * PARCBufferComposer *composer = parcBufferComposer_Create();
+ *
+ * parcURIPath_BuildString(path, composer);
+ *
+ * PARCBuffer *string = parcBufferComposer_ProducerBuffer(composer);
+ * printf("URI: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcURIPath_BuildString(const PARCURIPath *path, PARCBufferComposer *composer);
+
+/**
+ * Determine if a `PARCURIPath` begins with the specified URI prefix.
+ *
+ * @param [in] base The `PARCURIPath` instance which is being checked.
+ * @param [in] prefix The `PARCURIPath` prefix used to check as the prefix.
+ *
+ * @return true If the base is prefixed with the given `PARCURIPath`
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *whole = parcURIPath_Parse("lci:/foo/bar, &pointer);
+ * PARCURIPath *prefix = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * bool isPrefix(whole, prefix); // returns true
+ * }
+ * @endcode
+ */
+bool parcURIPath_StartsWith(const PARCURIPath *base, const PARCURIPath *prefix);
+
+/**
+ * Determine the length of the given `PARCURIPath` instance.
+ *
+ * @param [in] path The `PARCURIPath` instance which is being examined.
+ *
+ * @return The length of the `PARCURIPath`, in terms of the number of segments.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * size_t lengthOfPath = parcURIPath_Length(path); // returns 2
+ * }
+ * @endcode
+ */
+size_t parcURIPath_Length(const PARCURIPath *path);
+#endif // libparc_PARCURIPath_h
diff --git a/libparc/parc/algol/parc_URISegment.c b/libparc/parc/algol/parc_URISegment.c
new file mode 100755
index 00000000..7261c3aa
--- /dev/null
+++ b/libparc/parc/algol/parc_URISegment.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URISegment.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_uri_segment {
+ PARCBuffer *buffer;
+ bool requiresEscaping;
+};
+
+static char *hexDigitsUpper = "0123456789ABCDEF";
+static char *hexDigitsLower = "0123456789abcdef";
+
+// Given a value, return the low nibble as a hex character.
+static char
+_toHexDigit(const char value)
+{
+ return hexDigitsUpper[value & 0xF];
+}
+
+/**
+ * @function _fromHexDigit
+ * @abstract Given a hex character, return the decimal value.
+ * @discussion
+ * Given a simple character containing the ASCII value for a hexadecimal digit, return the actual value.
+ *
+ * @param hexDigit A hexadecimal digit as a character from the set of characters <code>0123456789ABCDEFabcdef</code>
+ * @return Return the decimal value of the given hex character. If not a hex character return a value > 15.
+ */
+static char
+_fromHexDigit(const char hexDigit)
+{
+ for (char i = 0; i < 16; i++) {
+ if (hexDigit == hexDigitsLower[(int) i] || hexDigit == hexDigitsUpper[(int) i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static const char *
+_parsePercentEncoded(const char *string, unsigned char *value)
+{
+ char c = *string++;
+ if (c != 0) {
+ unsigned char hi = _fromHexDigit(c);
+ if (hi > 15) {
+ return NULL;
+ }
+ c = *string++;
+ if (c != 0) {
+ unsigned char lo = _fromHexDigit(c);
+ if (lo > 15) {
+ return NULL;
+ }
+ *value = (unsigned char) (hi << 4 | lo);
+ return string;
+ }
+ }
+ return NULL;
+}
+
+#define uriPlainSegmentChar(c) (c != 0 && strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~", c) != NULL)
+
+static PARCBufferComposer *
+_parcURISegment_BuildString(const PARCURISegment *segment, PARCBufferComposer *composer)
+{
+ assertNotNull(composer, "Parameter must be a non-null pointer to a PARCBufferComposer.");
+
+ for (size_t i = 0; i < parcBuffer_Limit(segment->buffer) && composer != NULL; i++) {
+ unsigned char c = parcBuffer_GetAtIndex(segment->buffer, i);
+ if (uriPlainSegmentChar(c)) {
+ parcBufferComposer_PutChar(composer, c);
+ } else {
+ parcBufferComposer_PutChar(composer, '%');
+ parcBufferComposer_PutChar(composer, _toHexDigit(c >> 4));
+ parcBufferComposer_PutChar(composer, _toHexDigit(c));
+ }
+ }
+
+ return composer;
+}
+
+static void
+_parcURISegment_Finalize(PARCURISegment **segmentPtr)
+{
+ PARCURISegment *segment = *segmentPtr;
+
+ parcBuffer_Release(&(segment->buffer));
+}
+
+parcObject_ExtendPARCObject(PARCURISegment, _parcURISegment_Finalize, parcURISegment_Clone, parcURISegment_ToString,
+ parcURISegment_Equals, parcURISegment_Compare, NULL, NULL);
+
+PARCURISegment *
+parcURISegment_CreateFromBuffer(PARCBuffer *buffer)
+{
+ PARCURISegment *result = parcObject_CreateInstance(PARCURISegment);
+ if (result != NULL) {
+ result->buffer = parcBuffer_Acquire(buffer);
+ }
+ return result;
+}
+
+PARCURISegment *
+parcURISegment_Create(size_t length, const unsigned char segment[length])
+{
+ PARCURISegment *result = NULL;
+
+ PARCBuffer *buffer = parcBuffer_Allocate(length);
+ if (buffer != NULL) {
+ parcBuffer_PutArray(buffer, length, segment);
+ parcBuffer_Flip(buffer);
+ result = parcURISegment_CreateFromBuffer(buffer);
+ parcBuffer_Release(&buffer);
+ }
+ return result;
+}
+
+PARCURISegment *
+parcURISegment_Parse(const char *string, const char **pointer)
+{
+ assertFalse(*string == '/', "Input parameter '%s' must NOT point to an initial '/' character.", string);
+
+ unsigned char *segment = parcMemory_AllocateAndClear((strlen(string) + 1) * sizeof(unsigned char));
+ assertNotNull(segment, "parcMemory_AllocateAndClear(%zu) returned NULL", (strlen(string) + 1) * sizeof(unsigned char));
+ size_t length = 0;
+
+ unsigned char *r = segment;
+
+ const char *p = string;
+ while (*p && *p != '/' && *p != '?' && *p != '#') {
+ if (*p == '%') {
+ unsigned char value;
+ if ((p = _parsePercentEncoded(p + 1, &value)) == NULL) {
+ parcMemory_Deallocate((void **) &segment);
+ return NULL;
+ }
+ *r = value;
+ } else {
+ *r = *p++;
+ }
+ length++;
+ r++;
+ }
+ if (*p != 0) {
+ // absorb any extra slash characters.
+ while (p[1] == '/') {
+ p++;
+ }
+ }
+
+ PARCURISegment *result = parcURISegment_Create(length, segment);
+ parcMemory_Deallocate((void **) &segment);
+ if (pointer != NULL) {
+ *pointer = p;
+ }
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURISegment, PARCURISegment);
+
+parcObject_ImplementRelease(parcURISegment, PARCURISegment);
+
+PARCBuffer *
+parcURISegment_GetBuffer(const PARCURISegment *segment)
+{
+ parcBuffer_Rewind(segment->buffer);
+ return segment->buffer;
+}
+
+size_t
+parcURISegment_Length(const PARCURISegment *segment)
+{
+ parcBuffer_Rewind(segment->buffer);
+ return parcBuffer_Remaining(segment->buffer);
+}
+
+bool
+parcURISegment_Equals(const PARCURISegment *segmentA, const PARCURISegment *segmentB)
+{
+ if (segmentA == segmentB) {
+ return true;
+ }
+ if (segmentA == NULL || segmentB == NULL) {
+ return false;
+ }
+ return parcBuffer_Equals(segmentA->buffer, segmentB->buffer);
+}
+
+PARCURISegment *
+parcURISegment_Clone(const PARCURISegment *segment)
+{
+ assertNotNull(segment, "Parameter must be a non-null PARC_URISegment pointer.");
+
+ PARCBuffer *copy = parcBuffer_Copy(segment->buffer);
+ PARCURISegment *result = parcURISegment_CreateFromBuffer(copy);
+ parcBuffer_Release(&copy);
+ return result;
+}
+
+int
+parcURISegment_Compare(const PARCURISegment *a, const PARCURISegment *b)
+{
+ if (a == NULL) {
+ if (b == NULL) {
+ return 0;
+ }
+ return -1;
+ } else {
+ if (b == NULL) {
+ return +1;
+ }
+ }
+
+ if (parcURISegment_Length(a) < parcURISegment_Length(b)) {
+ return -1;
+ }
+ if (parcURISegment_Length(a) > parcURISegment_Length(b)) {
+ return +1;
+ }
+ return parcBuffer_Compare(a->buffer, b->buffer);
+}
+
+PARCBufferComposer *
+parcURISegment_BuildString(const PARCURISegment *segment, PARCBufferComposer *composer)
+{
+ composer = _parcURISegment_BuildString(segment, composer);
+
+ return composer;
+}
+
+char *
+parcURISegment_ToString(const PARCURISegment *segment)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char *result = NULL;
+
+ if (parcURISegment_BuildString(segment, composer)) {
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_URISegment.h b/libparc/parc/algol/parc_URISegment.h
new file mode 100644
index 00000000..e7234d3f
--- /dev/null
+++ b/libparc/parc/algol/parc_URISegment.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_URISegment.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier (URI) Segment
+ *
+ */
+#ifndef libparc_parc_URISegment_h
+#define libparc_parc_URISegment_h
+
+#include <parc/algol/parc_BufferComposer.h>
+
+struct parc_uri_segment;
+typedef struct parc_uri_segment PARCURISegment;
+
+/**
+ * Create a `PARCURISegment` instance copying data from the given pointer and length.
+ *
+ * A `PARCURISegment` is a tuple consisting of a pointer to arbitrary memory containing the first byte
+ * of `length` bytes as the value of the segment.
+ *
+ * Since the input parameter `pointer` points to arbitrary memory,
+ * this function makes a private copy of the data.
+ *
+ * @param [in] length The length of the given array pointed to by @p segment.
+ * @param [in] segment A pointer to an array consisting of at least @p length bytes.
+ *
+ * @return A `PARCURISegment` instance referring to the given pointer and length.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segment = parcURISegment_Create(5, "Hello");
+ * ...
+ * parcURISegment_Release(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURISegment_Create(size_t length, const unsigned char *segment);
+
+/**
+ * Create a `PARCURISegment` instance referencing the given {@link PARCBuffer}.
+ *
+ * A new reference to the given `PARCBuffer` is acquired.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return A `PARCURISegment` instance referring to the given `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("lci:/foo/bar", 12, 0, 12);
+ * PARCURISegment *segment = parcURISegment_CreateFromBuffer(buffer);
+ * ...
+ * parcURISegment_Release(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURISegment_CreateFromBuffer(PARCBuffer *buffer);
+
+/**
+ * Increase the number of references to a `PARCURISegment`.
+ *
+ * Note that new `PARCURISegment` is not created,
+ * only that the given `PARCURISegment` reference count is incremented.
+ * Discard the reference by invoking {@link parcURISegment_Release}.
+ *
+ * @param [in] segment A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *x = parcURISegment_Create(5, "Hello");
+ *
+ * PARCURISegment *x2 = parcURISegment_Acquire(x);
+ *
+ * parcURISegment_Release(&x);
+ * parcURISegment_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcURISegment_Release}
+ */
+PARCURISegment *parcURISegment_Acquire(const PARCURISegment *segment);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] segmentPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *x = parcURISegment_Create(5, "Hello");
+ *
+ * parcURISegment_Release(&x);
+ * }
+ * @endcode
+ */
+void parcURISegment_Release(PARCURISegment **segmentPtr);
+
+/**
+ * Compares two `PARCURISegment` instances for order.
+ *
+ * As strings, URI segments are compared in normal lexographical order. This
+ * is analogous to strcmp(...).
+ *
+ * @param [in] a A `PARCURISegment` pointer, or NULL.
+ * @param [in] b A `PARCURISegment` pointer, or NULL.
+ *
+ * @return A negative integer, zero, or a positive integer as a is less than, equal to, or greater than b, accordingly.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segmentA = parcURISegment_Create(6, "HelloA");
+ * PARCURISegment *segmentB = parcURISegment_Create(6, "HelloB");
+ * int cmp = parcURISegment_Compare(segmentA, segmentB);
+ * // cmp will be a negative integer since "HelloA" < "HelloB"
+ * }
+ * @endcode
+ */
+int parcURISegment_Compare(const PARCURISegment *a, const PARCURISegment *b);
+
+/**
+ * Create an independant copy the given `PARCURISegment`
+ *
+ * A new URI segment is created as a complete copy of the original.
+ *
+ * @param [in] segment A pointer to a `PARCURISegment` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCURISegment` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segment = parcURISegment_Create(5, "Hello");
+ * PARCURISegment *copy = parcURISegment_Clone(segment);
+ *
+ * // use either segment or copy as needed
+ *
+ * parcBuffer_Release(&copy);
+ * parcBuffer_Release(&segment);
+ * }
+ * @endcode
+ *
+ */
+PARCURISegment *parcURISegment_Clone(const PARCURISegment *segment);
+
+/**
+ * Determine if two `PARCURISegment` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCURISegment` instances are maintained
+ *
+ * * It is reflexive: for any non-null reference value x, `parcURISegment_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcURISegment_Equals(x, y)` must return true if and only if
+ * `parcURISegment_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcURISegment_Equals(x, y)` returns true and
+ * `parcURISegment_Equals(y, z)` returns true,
+ * then `parcURISegment_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcURISegment_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcURISegment_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCURISegment` instance.
+ * @param [in] y A pointer to a `PARCURISegment` instance.
+ *
+ * @return true `PARCURISegment` x and y are equal.
+ * @return false `PARCURISegment` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segmentA = parcURISegment_Create(5, "Hello");
+ * PARCURISegment *segmentB = parcURISegment_Create(5, "Hello");
+ *
+ * if (parcURISegment_Equals(segmentA, segmentB)) {
+ * printf("The URI segments are equal\n");
+ * } else {
+ * printf("The URI segments are NOT equal\n");
+ * }
+ *
+ * parcURISegment_Equals(&segmentA);
+ * parcURISegment_Equals(&segmentB);
+ * }
+ * @endcode
+ */
+bool parcURISegment_Equals(const PARCURISegment *x, const PARCURISegment *y);
+
+/**
+ * Parse a single URI segment.
+ *
+ * The input parameter string must point to a '/' which indicates the beginning of a segment.
+ * The segment is terminated by a null byte or a '?' or '#' character and may may be zero length.
+ * The output parameter pointer will be assigned the address of the first character that is not part of the parsed segment.
+ *
+ * The returned value must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] string Pointer to the beginning of the segment
+ * @param [in,out] pointer Will be assigned the address of the first character that is not part of the parsed segment.
+ *
+ * @return An allocated `PARCURISegment` the must be deallocated via `parcMemory_Deallocate`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURISegment *segment = parcURISegment_Parse("lci:/a/b/", &pointer);
+ * ...
+ * parcBuffer_Release(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURISegment_Parse(const char *string, const char **pointer);
+
+/**
+ * Get the {@link PARCBuffer} containing the content of the given URI segment.
+ *
+ * The PARCBuffer is always rewound (see {@link parcBuffer_Rewind}).
+ *
+ * @param [in] segment A `PARCURISegment` instance from which the buffer will be extracted.
+ *
+ * @return A `PARCBuffer` instance containing the URI segment bytes that must be freed via {@link parcBuffer_Release()}
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segment = parcURISegment_Create(5, "Hello");
+ * PARCBuffer *segBuffer = parcURISegment_GetBuffer(segment);
+ * // use or display the segment buffer as needed...
+ *
+ * parcURISegment(&segment);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcURISegment_GetBuffer(const PARCURISegment *segment);
+
+/**
+ * Append a representation of the specified instance to the given {@link PARCBufferComposer}.
+ *
+ * The URI representation is escape-encoded for all characters specified
+ *
+ * @param [in] component A pointer to the instance to be appended to @p composer.
+ * @param [in,out] composer A `PARCBufferComposer` to which this URI segment is appended.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcURISegment_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("URI: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcURISegment_BuildString(const PARCURISegment *component, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCURISegment` instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * The result is percent-encoding if necessary.
+ * A `PARCURISegment` may contain characters that are not permitted in the path in their native form.
+ * These characters must be 'percent encoded' using the '%' followed by the hexadecimal value of the character.
+ * For consistency, percent-encoded octets in the ranges of
+ * ALPHA (%41-%5A and %61-%7A),
+ * DIGIT (%30-%39),
+ * hyphen (%2D),
+ * period (%2E),
+ * underscore (%5F),
+ * or tilde (%7E)
+ * should not be created by URI producers and,
+ * when found in a URI,
+ * should be decoded to their corresponding unreserved characters by URI normalizers.
+ *
+ * @param [in] segment A pointer to the instance.
+ *
+ * @return An allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *instance = parcURISegment_Create(5, "Hello");
+ *
+ * char *string = parcURISegment_ToString(instance);
+ *
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ *
+ * parcURISegment_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcURISegment_Parse
+ */
+char *parcURISegment_ToString(const PARCURISegment *segment);
+
+/**
+ * Get the length, in bytes, of the given `PARCURISegment`.
+ *
+ * @param [in] segment A pointer to the segment to inspect.
+ *
+ * @return The length, in bytes, of the given `PARCURISegment`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *instance = parcURISegment_Create(5, "Hello");
+ * size_t length = parcURISegment_Length(instance);
+ * // length will be 5
+ * }
+ * @endcode
+ */
+size_t parcURISegment_Length(const PARCURISegment *segment);
+#endif // libparc_parc_URISegment_h
diff --git a/libparc/parc/algol/parc_Unsigned.c b/libparc/parc/algol/parc_Unsigned.c
new file mode 100644
index 00000000..839f6b2b
--- /dev/null
+++ b/libparc/parc/algol/parc_Unsigned.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <stdio.h>
+#include <config.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/algol/parc_Unsigned.h>
+
+struct PARCUnsigned {
+ unsigned x;
+};
+
+static bool
+_parcUnsigned_Destructor(PARCUnsigned **instancePtr)
+{
+ return true;
+}
+
+parcObject_ImplementAcquire(parcUnsigned, PARCUnsigned);
+
+parcObject_ImplementRelease(parcUnsigned, PARCUnsigned);
+
+parcObject_Override(PARCUnsigned, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcUnsigned_Destructor,
+ .copy = (PARCObjectCopy *) parcUnsigned_Copy,
+ .display = (PARCObjectDisplay *) parcUnsigned_Display,
+ .toString = (PARCObjectToString *) parcUnsigned_ToString,
+ .equals = (PARCObjectEquals *) parcUnsigned_Equals,
+ .compare = (PARCObjectCompare *) parcUnsigned_Compare,
+ .hashCode = (PARCObjectHashCode *) parcUnsigned_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcUnsigned_ToJSON,
+ .display = (PARCObjectDisplay *) parcUnsigned_Display);
+
+void
+parcUnsigned_AssertValid(const PARCUnsigned *instance)
+{
+ assertTrue(parcUnsigned_IsValid(instance),
+ "PARCUnsigned is not valid.");
+}
+
+PARCUnsigned *
+parcUnsigned_Create(unsigned x)
+{
+ PARCUnsigned *result = parcObject_CreateInstance(PARCUnsigned);
+ if (result != NULL) {
+ result->x = x;
+ }
+ return result;
+}
+
+int
+parcUnsigned_Compare(const PARCUnsigned *val, const PARCUnsigned *other)
+{
+ int result = 0;
+
+ if (val == NULL) {
+ if (other != NULL) {
+ result = -1;
+ }
+ } else if (other == NULL) {
+ result = 1;
+ } else {
+ parcUnsigned_OptionalAssertValid(val);
+ parcUnsigned_OptionalAssertValid(other);
+
+ if (val->x < other->x) {
+ return -1;
+ } else if (val->x > other->x) {
+ return 1;
+ }
+ }
+
+ return result;
+}
+
+PARCUnsigned *
+parcUnsigned_Copy(const PARCUnsigned *original)
+{
+ PARCUnsigned *result = parcUnsigned_Create(original->x);
+
+ return result;
+}
+
+void
+parcUnsigned_Display(const PARCUnsigned *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCSUnsingned@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->x);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcUnsigned_Equals(const PARCUnsigned *x, const PARCUnsigned *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ parcUnsigned_OptionalAssertValid(x);
+ parcUnsigned_OptionalAssertValid(y);
+
+ if (x->x == y->x) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcUnsigned_HashCode(const PARCUnsigned *x)
+{
+ PARCHashCode result = 0;
+
+ result = parcHashCode_Hash((uint8_t *) &(x->x), sizeof(x->x));
+
+ return result;
+}
+
+bool
+parcUnsigned_IsValid(const PARCUnsigned *x)
+{
+ bool result = false;
+
+ if (x != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcUnsigned_ToJSON(const PARCUnsigned *x)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcUnsigned_ToString(const PARCUnsigned *x)
+{
+ int length = snprintf(NULL, 0, "%d", x->x);
+ char*str = malloc(length + 1);
+ snprintf(str, length + 1, "%d", x->x);
+ return str;
+}
+
+unsigned
+parcUnsigned_GetUnsigned(const PARCUnsigned *x)
+{
+ parcUnsigned_OptionalAssertValid(x);
+
+ return x->x;
+}
diff --git a/libparc/parc/algol/parc_Unsigned.h b/libparc/parc/algol/parc_Unsigned.h
new file mode 100755
index 00000000..b61195e4
--- /dev/null
+++ b/libparc/parc/algol/parc_Unsigned.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Unsigned.h
+ * @ingroup types
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Unsigned
+#define PARCLibrary_parc_Unsigned
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+typedef struct PARCUnsigned PARCUnsigned;
+extern parcObjectDescriptor_Declaration(PARCUnsigned);
+
+/**
+ */
+PARCUnsigned *parcUnsigned_Acquire(const PARCUnsigned *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcUnsigned_OptionalAssertValid(_instance_)
+#else
+# define parcUnsigned_OptionalAssertValid(_instance_) parcUnsigned_AssertValid(_instance_)
+#endif
+
+/**
+ */
+void parcUnsinged_AssertValid(const PARCUnsigned *instance);
+
+/**
+ */
+PARCUnsigned *parcUnsigned_Create(unsigned x);
+
+
+/**
+ */
+int parcUnsigned_Compare(const PARCUnsigned *instance, const PARCUnsigned *other);
+
+/**
+ */
+PARCUnsigned *parcUnsigned_Copy(const PARCUnsigned *original);
+
+/**
+ */
+void parcUnsigned_Display(const PARCUnsigned *instance, int indentation);
+
+/**
+ */
+bool parcUnsigned_Equals(const PARCUnsigned *x, const PARCUnsigned *y);
+
+/**
+ */
+PARCHashCode parcUnsigned_HashCode(const PARCUnsigned *instance);
+
+/**
+ */
+bool parcUnsigned_IsValid(const PARCUnsigned *instance);
+
+/**
+ */
+void parcUnsigned_Release(PARCUnsigned **instancePtr);
+
+/**
+ */
+PARCJSON *parcUnsigned_ToJSON(const PARCUnsigned *instance);
+
+/**
+ */
+char *parcUnsigned_ToString(const PARCUnsigned *instance);
+
+/**
+ */
+unsigned parcUnsigned_GetUnsigned(const PARCUnsigned *istance);
+#endif
diff --git a/libparc/parc/algol/parc_Varint.c b/libparc/parc/algol/parc_Varint.c
new file mode 100755
index 00000000..7a593f45
--- /dev/null
+++ b/libparc/parc/algol/parc_Varint.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <parc/algol/parc_Varint.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_varint {
+ uint64_t value;
+};
+
+PARCVarint *
+parcVarint_Create(void)
+{
+ PARCVarint *result = parcMemory_AllocateAndClear(sizeof(PARCVarint));
+ if (result != NULL) {
+ result->value = 0;
+ }
+ return result;
+}
+
+PARCVarint *
+parcVarint_DecodeBuffer(PARCBuffer *buffer, size_t length)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ assertTrue(length < sizeof(size_t), "Length must be less then or equal to %zd", sizeof(size_t));
+ assertTrue(length <= parcBuffer_Remaining(buffer), "Buffer does not contain at least %zd bytes", length);
+
+ PARCVarint *result = parcVarint_Create();
+ assertNotNull(result, "PARCVarint out of memory.");
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_ShiftLeft(result, 8);
+ parcVarint_OrUint8(result, parcBuffer_GetUint8(buffer));
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_DecodeElasticByteBuffer(const PARCBuffer *buffer, size_t length)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ assertTrue(length < sizeof(size_t), "Length must be less then or equal to %zd", sizeof(size_t));
+
+ PARCVarint *result = parcVarint_Create();
+ assertNotNull(result, "PARCVarint out of memory.");
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_ShiftLeft(result, 8);
+ parcVarint_OrUint8(result, parcBuffer_GetAtIndex(buffer, i));
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_Set(PARCVarint *varint, uint64_t newValue)
+{
+ varint->value = newValue;
+ return varint;
+}
+
+PARCVarint *
+parcVarint_FromElasticByteBuffer(const PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ PARCVarint *result = parcVarint_Create();
+
+ size_t length = parcBuffer_Remaining(buffer);
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_ShiftLeft(result, 8);
+ parcVarint_OrUint8(result, parcBuffer_GetAtIndex(buffer, i));
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_FromUTF8ByteBuffer(const PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must not be NULL.");
+ PARCVarint *result = parcVarint_Create();
+
+ if (result != NULL) {
+ size_t length = parcBuffer_Remaining(buffer);
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_Multiply(result, 10);
+ parcVarint_Add(result, parcBuffer_GetAtIndex(buffer, i) - '0');
+ }
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_FromUTF8Buffer(PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ PARCVarint *result = parcVarint_Create();
+
+ if (result != NULL) {
+ size_t length = parcBuffer_Limit(buffer);
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_Multiply(result, 10);
+ parcVarint_Add(result, parcBuffer_GetAtIndex(buffer, i) - '0');
+ }
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @param uint
+ * @return
+ */
+PARCVarint *
+parcVarint_FromUint8(uint8_t uint)
+{
+ return parcVarint_FromUint32(uint);
+}
+
+/**
+ *
+ * @param uint
+ * @return
+ */
+PARCVarint *
+parcVarint_FromUint32(uint32_t uint)
+{
+ return parcVarint_FromUint64(uint);
+}
+
+/**
+ *
+ * @param uint
+ * @return
+ */
+PARCVarint *
+parcVarint_FromUint64(uint64_t uint)
+{
+ PARCVarint *result = parcMemory_AllocateAndClear(sizeof(PARCVarint));
+ if (result != NULL) {
+ result->value = uint;
+ }
+ return result;
+}
+
+/**
+ *
+ * @param varintP
+ */
+void
+parcVarint_Destroy(PARCVarint **varintP)
+{
+ assertNotNull(varintP, "Parameter must be a non-null pointer to a pointer to a PARCVarint");
+ assertNotNull(*varintP, "Parameter must be a non-null pointer to a PARCVarint");
+
+ parcMemory_Deallocate((void **) varintP);
+ *varintP = NULL;
+}
+
+/**
+ * Shift the value {@code bits} to the left.
+ *
+ * @param varint
+ * @param bits
+ * @return
+ */
+PARCVarint *
+parcVarint_ShiftLeft(PARCVarint *varint, int bits)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value <<= bits;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Add(PARCVarint *varint, int addend)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value += addend;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Subtract(PARCVarint *varint, int subtrahend)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value -= subtrahend;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Multiply(PARCVarint *varint, int multiplicand)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value *= multiplicand;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Divide(PARCVarint *varint, int divisor)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value /= divisor;
+
+ return varint;
+}
+
+/**
+ * Shift the value {@code bits} to the right.
+ *
+ * @param varint
+ * @param bits
+ * @return
+ */
+PARCVarint *
+parcVarint_ShiftRight(PARCVarint *varint, int bits)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value >>= bits;
+ return varint;
+}
+
+/**
+ * Perform an AND operation on the given {@link PARCVarint} with the supplied {@code operand},
+ * leaving the result in {@code varint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_And(PARCVarint *varint, PARCVarint *operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ assertNotNull(operand, "Parameter operand must not be NULL.");
+ varint->value &= operand->value;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint8(PARCVarint *varint, uint8_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint16(PARCVarint *varint, uint16_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint32(PARCVarint *varint, uint32_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint64(PARCVarint *varint, uint64_t operand)
+{
+ assertNotNull(varint, "Parameter must be a non-null PARCVarint pointer.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_Or(PARCVarint *varint, PARCVarint *operand)
+{
+ assertNotNull(varint, "Parameter must be a non-null PARCVarint pointer.");
+ varint->value |= operand->value;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 8-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint8(PARCVarint *varint, uint8_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 16-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint16(PARCVarint *varint, uint16_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 32-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint32(PARCVarint *varint, uint32_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 64-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint64(PARCVarint *varint, uint64_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Return {@code true} (non-zero) if the two {@link PARCVarint} structures contain equal data.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+int
+parcVarint_Equals(PARCVarint *varint, PARCVarint *operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return varint->value == operand->value;
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint64(PARCVarint *varint, uint64_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return varint->value == value;
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint32(PARCVarint *varint, uint32_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return parcVarint_EqualsUint64(varint, (uint64_t) value);
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint16(PARCVarint *varint, uint16_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return parcVarint_EqualsUint64(varint, (uint64_t) value);
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint8(PARCVarint *varint, uint8_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return parcVarint_EqualsUint64(varint, (uint64_t) value);
+}
+
+/**
+ * Produce the 8 low-order bits of this {@code PARCVarint}.
+ *
+ * @param varint
+ * @return
+ */
+uint8_t
+parcVarint_AsUint8(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (uint8_t) varint->value;
+}
+
+/**
+ * Produce the 16 low-order bits of this {@code PARCVarint}.
+ *
+ * @param varint
+ * @return
+ */
+uint16_t
+parcVarint_AsUint16(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (uint16_t) varint->value;
+}
+
+/**
+ * Produce the 32 low-order bits of this {@code PARCVarint}.
+ *
+ * @param varint
+ * @return
+ */
+uint32_t
+parcVarint_AsUint32(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (uint32_t) varint->value;
+}
+
+uint64_t
+parcVarint_AsUint64(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return varint->value;
+}
+
+/**
+ * Produce the value of this {@code PARCVarint} as a {@code size_t} value.
+ *
+ * @param varint
+ * @return
+ */
+size_t
+parcVarint_AsSize(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (size_t) varint->value;
+}
+
+/**
+ * Produce a string representation of this {@link PARCVarint}.
+ * The returned value must be freed by the called using the {@code stdlib.h} {@code free}.
+ * @param string
+ * @param varint
+ * @return
+ */
+char *
+parcVarint_ToString(char **string, PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ int nwritten = asprintf(string, "%" PRIu64, varint->value);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+ return *string;
+}
diff --git a/libparc/parc/algol/parc_Varint.h b/libparc/parc/algol/parc_Varint.h
new file mode 100755
index 00000000..6d7e60b8
--- /dev/null
+++ b/libparc/parc/algol/parc_Varint.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Varint.h
+ * @ingroup datastructures
+ * @brief A Variable Length Integer.
+ *
+ * A variable length integer.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libparc_parc_VarInt_h
+#define libparc_parc_VarInt_h
+
+#include <stdint.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+/**
+ * A variable length integer value.
+ * <em>
+ * This particular implementation is limited to a 64 bit value.
+ * </em>
+ */
+struct parc_varint;
+typedef struct parc_varint PARCVarint;
+
+
+#define PARC_VARINT_INIT { 0 }
+
+/**
+ * Create a new instance of `PARCVarint`
+ *
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Create(void);
+
+/**
+ * Decode an instance of {@link PARCBuffer} of length @p length into a new instance of `PARCVarInt`
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer`.
+ * @param [in] length The number of bytes to decode.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode */
+PARCVarint *parcVarint_DecodeBuffer(PARCBuffer *buffer, size_t length);
+
+/**
+ * Decode an instance of {@link PARCBuffer} of length @p length into a new instance of `PARCVarInt`
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer`.
+ * @param [in] length The number of bytes to decode.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_DecodeElasticByteBuffer(const PARCBuffer *buffer, size_t length);
+
+/**
+ * Create a new `PARCVarint` from bytes in a {@link PARCBuffer}.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer`.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_FromElasticByteBuffer(const PARCBuffer *buffer);
+
+/**
+ * Create a `PARCVarint` with the value decoded from the given {@link PARCBuffer}
+ * containing a UTF-8 string encoded number.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` containing a UTF-8 string encoded number.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_FromUTF8Buffer(PARCBuffer *buffer);
+
+/**
+ * Create a `PARCVarint` with the value decoded from the given {@link PARCBuffer}
+ * containing a UTF-8 string encoded number.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` containing a UTF-8 string encoded number.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ */
+PARCVarint *parcVarint_FromUTF8ByteBuffer(const PARCBuffer *buffer);
+
+
+extern PARCVarint *parcVarint_FromUint8(uint8_t uint);
+
+extern PARCVarint *parcVarint_FromUint32(uint32_t uint);
+
+extern PARCVarint *parcVarint_FromUint64(uint64_t uint);
+
+extern PARCVarint *parcVarint_ShiftLeft(PARCVarint *varint, int bits);
+
+extern PARCVarint *parcVarint_ShiftRight(PARCVarint *varint, int bits);
+
+extern PARCVarint *parcVarint_And(PARCVarint *varint, PARCVarint *operand);
+
+extern PARCVarint *parcVarint_AndUint8(PARCVarint *varint, uint8_t operand);
+
+extern PARCVarint *parcVarint_AndUint16(PARCVarint *varint, uint16_t operand);
+
+extern PARCVarint *parcVarint_AndUint32(PARCVarint *varint, uint32_t operand);
+
+extern PARCVarint *parcVarint_AndUint64(PARCVarint *varint, uint64_t operand);
+
+extern PARCVarint *parcVarint_Or(PARCVarint *varint, PARCVarint *operand);
+
+extern PARCVarint *parcVarint_OrUint8(PARCVarint *varint, uint8_t operand);
+
+extern PARCVarint *parcVarint_OrUint16(PARCVarint *varint, uint16_t operand);
+
+extern PARCVarint *parcVarint_OrUint32(PARCVarint *varint, uint32_t operand);
+
+extern PARCVarint *parcVarint_OrUint64(PARCVarint *varint, uint64_t operand);
+
+/**
+ * Determine if two `PARCVarint` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcVarint_Equals(x, y)` must return true if and only if
+ * `parcVarint_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Equals(x, y)` returns true and
+ * `parcVarint_Equals(y, z)` returns true,
+ * then `parcVarint_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param varint A pointer to a `PARCVarint` instance.
+ * @param operand A pointer to a `PARCVarint` instance.
+ * @return true if the two `PARCVarint` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * PARCVarint *b = parcVarint_Create();
+ *
+ * if (parcVarint_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+
+extern int parcVarint_Equals(PARCVarint *varint, PARCVarint *operand);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to a 64bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint64Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint64Equals(x, y)` may not return true even if
+ * `parcVarint_Uint64Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint64Equals(x, y)` returns true and
+ * `parcVarint_Uint64Equals(y, z)` returns true,
+ * then `parcVarint_Uint64Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint64Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint64Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint64_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint64_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint64Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint64(PARCVarint *varint, uint64_t value);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to a 32 bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint32Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint32Equals(x, y)` may not return true even if
+ * `parcVarint_Uint32Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint32Equals(x, y)` returns true and
+ * `parcVarint_Uint32Equals(y, z)` returns true,
+ * then `parcVarint_Uint32Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint32Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint32Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint32_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint32_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint32Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint32(PARCVarint *varint, uint32_t value);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to a 16 bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint16Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint16Equals(x, y)` may not return true even if
+ * `parcVarint_Uint16Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint16Equals(x, y)` returns true and
+ * `parcVarint_Uint16Equals(y, z)` returns true,
+ * then `parcVarint_Uint16Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint16Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint16Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint16_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint16_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint16Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint16(PARCVarint *varint, uint16_t value);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to an 8 bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint8Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint8Equals(x, y)` may not return true even if
+ * `parcVarint_Uint8Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint8Equals(x, y)` returns true and
+ * `parcVarint_Uint8Equals(y, z)` returns true,
+ * then `parcVarint_Uint8Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint8Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint8Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint8_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint8_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint8Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint8(PARCVarint *varint, uint8_t value);
+
+extern void parcVarint_Destroy(PARCVarint **varintP);
+
+extern char *parcVarint_ToString(char **string, PARCVarint *varint);
+
+extern uint8_t parcVarint_AsUint8(const PARCVarint *varint);
+
+extern uint16_t parcVarint_AsUint16(const PARCVarint *varint);
+
+extern uint32_t parcVarint_AsUint32(const PARCVarint *varint);
+
+/**
+ * Produce the 16 low-order bits of this `PARCVarint` as a `uint8_t`.
+ *
+ * @param [in] varint The inpu instance of `PARCVarint`
+ * @return The 16 low-order bits as a `uint8_t`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t parcVarint_AsUint64(const PARCVarint *varint);
+
+/**
+ * Return the value of the given `PARCVarint` cast as a `size_t`
+ *
+ * @param [in] varint The `PARCVarint` to cast as a `size_t`
+ *
+ * @return The given `PARCVarint` cast as a `size_t`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcVarint_AsSize(const PARCVarint *varint);
+
+/**
+ * Set the value of the given `PARCVarint` to the given value.
+ *
+ * @param [in,out] varint The `PARCVarint` to be modified
+ * @param [in] newValue The new value for the `PARCVarint`
+ * @return The modified `PARCVarint`.
+ */
+PARCVarint *parcVarint_Set(PARCVarint *varint, uint64_t newValue);
+
+/**
+ * Multiply the `PARCVarint`
+ *
+ * @param [in,out] varint The `PARCVarint` to be multiplied by the @p multiplicand
+ * @param [in] multiplicand The multiplicand to multiply by
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Multiply(PARCVarint *varint, int multiplicand);
+
+/**
+ * Divide the `PARCVarint` by a divisor
+ *
+ * @param [in,out] varint The `PARCVarint` to be divided by the @p divisor
+ * @param [in] divisor The divisor to use
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Divide(PARCVarint *varint, int divisor);
+/**
+ * Multiply the `PARCVarint`
+ *
+ * @param [in,out] varint The `PARCVarint` to which the @p addend should be added
+ * @param [in] addend The number to add to the `PARCVarint`
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Add(PARCVarint *varint, int addend);
+
+/**
+ * Subtract the @p subtrahend from the `PARCVarint`.
+ *
+ * @param [in,out] varint The `PARCVarint` from which to subtract the @p subtrahend
+ * @param [in] subtrahend The number to subtract from the `PARCVarint`
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Subtract(PARCVarint *varint, int subtrahend);
+#endif // libparc_parc_VarInt_h
diff --git a/libparc/parc/algol/parc_Vector.c b/libparc/parc/algol/parc_Vector.c
new file mode 100755
index 00000000..f5380eb7
--- /dev/null
+++ b/libparc/parc/algol/parc_Vector.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Vector.h>
+
+struct parc_vector {
+ const void *pointer;
+ size_t length;
+};
+
+PARCVector *
+parcVector_Create(const void *pointer, const size_t length)
+{
+ PARCVector *result = parcMemory_AllocateAndClear(sizeof(PARCVector));
+ if (result != NULL) {
+ parcVector_Init(result, pointer, length);
+ }
+
+ return result;
+}
+
+PARCVector *
+parcVector_Init(PARCVector *vector, const void *pointer, const size_t length)
+{
+ assertNotNull(vector, "Parameter must be a non-null PARCVector pointer");
+
+ vector->pointer = pointer;
+ vector->length = length;
+ return vector;
+}
+
+void
+parcVector_Destroy(PARCVector **vectorPtr)
+{
+ assertNotNull(vectorPtr, "Parameter must be a non-null PARCVector pointer");
+ PARCVector *vector = *vectorPtr;
+ assertNotNull(vector, "Vector is already free or was not set.\n");
+
+ parcMemory_Deallocate((void **) &vector);
+ *vectorPtr = NULL;
+}
+
+const void *
+parcVector_GetPointer(const PARCVector *vector)
+{
+ assertNotNull(vector, "Parameter must be a non-null PARCVector pointer.");
+ return vector->pointer;
+}
+
+size_t
+parcVector_GetLength(const PARCVector *vector)
+{
+ assertNotNull(vector, "Parameter must be a non-null PARCVector pointer.");
+
+ return vector->length;
+}
+
diff --git a/libparc/parc/algol/parc_Vector.h b/libparc/parc/algol/parc_Vector.h
new file mode 100755
index 00000000..825fc635
--- /dev/null
+++ b/libparc/parc/algol/parc_Vector.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Vector.h
+ * @ingroup datastructures
+ * @brief PARC Vector
+ * A Vector consists of a pointer and associated length in bytes of data in memory.
+ *
+ *
+ */
+#ifndef libparc_parc_Vector_h
+#define libparc_parc_Vector_h
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct parc_vector;
+
+/**
+ * A `PARCVector` is a tuple consisting of an address and a length.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct parc_vector PARCVector;
+
+/**
+ * Create a new `PARCVector` consisting of a pointer and a length.
+ *
+ * @param [in] pointer A pointer to memory.
+ * @param [in] length The length, in bytes.
+ * @return An allocated `PARCVector` structure.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVector *parcVector_Create(const void *pointer, const size_t length);
+
+/**
+ * Initialise the given `PARCVector` to the given values.
+ *
+ * @param [in,out] vector A pointer to the instance of `PARCVector` to initialize
+ * @param [in] pointer A pointer to the memory with which to initialize @p vector.
+ * @param [in] length The length of the @p pointer contents.
+ * @return The pointer to the input @p vector.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVector *parcVector_Init(PARCVector *vector, const void *pointer, const size_t length);
+
+/**
+ * Get the memory pointer for this `PARCVector`.
+ *
+ * @param [in] vector A pointer to the instance of `PARCVector` from which to get the memory pointer.
+ * @return The memory pointer of @p vector
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const void *parcVector_GetPointer(const PARCVector *vector);
+
+/**
+ * Get the length of of the `PARCVector`
+ *
+ * @param [in] vector The `PARCVector` instance of interest.
+ * @return The length of @p vector.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcVector_GetLength(const PARCVector *vector);
+
+/**
+ * Destroy the instance of `PARCVector`
+ *
+ * @param [in,out] vector The pointer to the pointer to the `PARCVector` instance to destroy.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcVector_Destroy(PARCVector **vector);
+#endif // libparc_parc_Vector_h
diff --git a/libparc/parc/algol/test/.gitignore b/libparc/parc/algol/test/.gitignore
new file mode 100644
index 00000000..b520ab17
--- /dev/null
+++ b/libparc/parc/algol/test/.gitignore
@@ -0,0 +1,73 @@
+test_parc_ArrayList
+test_parc_AtomicInteger
+test_parc_Base64
+test_parc_BitVector
+test_parc_Buffer
+test_parc_BufferComposer
+test_parc_BufferDictionary
+test_parc_ByteArray
+test_parc_ByteBuffer
+test_parc_ByteBufferCodec
+test_parc_ByteBuffer_Codec
+test_parc_Clock
+test_parc_Deque
+test_parc_Dictionary
+test_parc_Digester
+test_parc_Digests
+test_parc_Digests
+test_parc_Display
+test_parc_ElasticBuffer
+test_parc_ElasticString
+test_parc_Environment
+test_parc_Event
+test_parc_EventBuffer
+test_parc_EventQueue
+test_parc_EventScheduler
+test_parc_EventSignal
+test_parc_EventSocket
+test_parc_EventTimer
+test_parc_Extent
+test_parc_ExtentArray
+test_parc_FileOutputStream
+test_parc_Hash
+test_parc_HashCode
+test_parc_HashCodeTable
+test_parc_HashMap
+test_parc_HashMap
+test_parc_HashTable
+test_parc_InputStream
+test_parc_Iterator
+test_parc_JSON
+test_parc_JSONArray
+test_parc_JSONPair
+test_parc_JSONParser
+test_parc_JSONValue
+test_parc_KeyValue
+test_parc_KeyedElement
+test_parc_LinkedList
+test_parc_List
+test_parc_Memory
+test_parc_Network
+test_parc_NewByteBuffer
+test_parc_Object
+test_parc_ObjectImpl
+test_parc_PathName
+test_parc_PointerArray
+test_parc_PriorityQueue
+test_parc_Properties
+test_parc_ReadOnlyBuffer
+test_parc_SafeMemory
+test_parc_SortedList
+test_parc_Stack
+test_parc_StdlibMemory
+test_parc_String
+test_parc_StructArray
+test_parc_Time
+test_parc_Tlv
+test_parc_TreeRedBlack
+test_parc_TreeMap
+test_parc_URI
+test_parc_VarInt
+test_parc_Varint
+test_parc_Vector
+test_parc_VectorArray
diff --git a/libparc/parc/algol/test/CMakeLists.txt b/libparc/parc/algol/test/CMakeLists.txt
new file mode 100644
index 00000000..4199f3de
--- /dev/null
+++ b/libparc/parc/algol/test/CMakeLists.txt
@@ -0,0 +1,76 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+configure_file(data.json data.json COPYONLY)
+
+set(TestsExpectedToPass
+ test_parc_ArrayList
+ test_parc_AtomicInteger
+ test_parc_Base64
+ test_parc_BitVector
+ test_parc_Buffer
+ test_parc_BufferChunker
+ test_parc_BufferComposer
+ test_parc_ByteArray
+ test_parc_Clock
+ test_parc_Chunker
+ test_parc_Deque
+ test_parc_Dictionary
+ test_parc_Display
+ test_parc_Environment
+ test_parc_Event
+ test_parc_EventBuffer
+ test_parc_EventQueue
+ test_parc_EventScheduler
+ test_parc_EventSignal
+ test_parc_EventSocket
+ test_parc_EventTimer
+ test_parc_File
+ test_parc_FileChunker
+ test_parc_FileInputStream
+ test_parc_FileOutputStream
+ test_parc_Hash
+ test_parc_HashCode
+ test_parc_HashCodeTable
+ test_parc_HashMap
+ test_parc_InputStream
+ test_parc_Iterator
+ test_parc_JSON
+ test_parc_JSONArray
+ test_parc_JSONPair
+ test_parc_JSONParser
+ test_parc_JSONValue
+ test_parc_KeyValue
+ test_parc_KeyedElement
+ test_parc_LinkedList
+ test_parc_List
+ test_parc_Memory
+ test_parc_Network
+ test_parc_Object
+ test_parc_PathName
+ test_parc_PriorityQueue
+ test_parc_Properties
+ test_parc_RandomAccessFile
+ test_parc_ReadOnlyBuffer
+ test_parc_SafeMemory
+ test_parc_SortedList
+ test_parc_Stack
+ test_parc_StdlibMemory
+ test_parc_String
+ test_parc_Time
+ test_parc_TreeMap
+ test_parc_TreeRedBlack
+ test_parc_URI
+ test_parc_URIAuthority
+ test_parc_URIPath
+ test_parc_URISegment
+ test_parc_Varint
+ test_parc_Vector
+ )
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/algol/test/_test_parc_URI.h b/libparc/parc/algol/test/_test_parc_URI.h
new file mode 100644
index 00000000..01d3afae
--- /dev/null
+++ b/libparc/parc/algol/test/_test_parc_URI.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * _test_parc_URI.h
+ * PARC Algol
+ */
+
+#ifndef PARC_Algol__test_parc_URI_h
+#define PARC_Algol__test_parc_URI_h
+
+#define URI_SCHEME "lci"
+
+#define URI_AUTHORITY_USERINFO "user:pass"
+#define URI_AUTHORITY_USERINFO_2 "user2:pass2"
+#define URI_AUTHORITY_HOSTNAME "parc.com"
+#define URI_AUTHORITY_HOSTNAME_2 "xerox.com"
+#define URI_AUTHORITY_LITERAL_HOSTNAME "127.0.0.1"
+#define URI_AUTHORITY_LITERAL_HOSTNAME6 "[::0]"
+#define URI_AUTHORITY_LITERAL_HOSTNAME6_2 "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]"
+#define URI_AUTHORITY_PORT_1 "1234"
+#define URI_AUTHORITY_PORT_2 "5678"
+
+#define URI_AUTHORITY URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_DIFFERENT_PORT URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_2
+#define URI_AUTHORITY_DIFFERENT_HOST URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME_2 ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_LITERAL_HOST URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_LITERAL_HOST6 URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME6 ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_LITERAL_HOST6_2 URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME6_2 ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_DIFFERENT_USER URI_AUTHORITY_USERINFO_2 "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_1
+
+#define URI_PATH_SEGMENT "%00%01%02-.%03%04_%05%06%07%08%09abcdefghijklmnopqrstuvwxyz"
+#define URI_PATH_SEGMENT_WITH_SLASHES URI_PATH_SEGMENT "//////"
+
+#define URI_PATH "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT
+
+#define URI_QUERY "x=1&y=2&z=3"
+
+#define URI_FRAGMENT "alphabetagamma"
+
+#define URI_FULL URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH "?" URI_QUERY "#" URI_FRAGMENT
+
+char *TEST_URI_SCHEME = URI_SCHEME;
+char *TEST_URI_AUTHORITY = URI_AUTHORITY;
+#endif // PARC_Algol__test_parc_URI_h
diff --git a/libparc/parc/algol/test/data.json b/libparc/parc/algol/test/data.json
new file mode 100644
index 00000000..a146f6ff
--- /dev/null
+++ b/libparc/parc/algol/test/data.json
@@ -0,0 +1,2614 @@
+{
+ "array" : [
+ {
+ "id": 6104546,
+ "name": "-REPONAME",
+ "full_name": "mralexgray/-REPONAME",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/-REPONAME",
+ "description": null,
+ "fork": false,
+ "url": "https://api.github.com/repos/mralexgray/-REPONAME",
+ "forks_url": "https://api.github.com/repos/mralexgray/-REPONAME/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/-REPONAME/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/-REPONAME/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/-REPONAME/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/-REPONAME/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/-REPONAME/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/-REPONAME/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/-REPONAME/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/-REPONAME/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/-REPONAME/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/-REPONAME/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/-REPONAME/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/-REPONAME/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/-REPONAME/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/-REPONAME/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/-REPONAME/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/-REPONAME/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/-REPONAME/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/-REPONAME/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/-REPONAME/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/-REPONAME/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/-REPONAME/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/-REPONAME/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/-REPONAME/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/-REPONAME/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/-REPONAME/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/-REPONAME/releases{/id}",
+ "created_at": "2012-10-06T16:37:39Z",
+ "updated_at": "2013-01-12T13:39:30Z",
+ "pushed_at": "2012-10-06T16:37:39Z",
+ "git_url": "git://github.com/mralexgray/-REPONAME.git",
+ "ssh_url": "git@github.com:mralexgray/-REPONAME.git",
+ "clone_url": "https://github.com/mralexgray/-REPONAME.git",
+ "svn_url": "https://github.com/mralexgray/-REPONAME",
+ "homepage": null,
+ "size": 48,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": true,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13121042,
+ "name": "ace",
+ "full_name": "mralexgray/ace",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ace",
+ "description": "Ace (Ajax.org Cloud9 Editor)",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ace",
+ "forks_url": "https://api.github.com/repos/mralexgray/ace/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ace/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ace/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ace/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ace/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ace/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ace/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ace/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ace/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ace/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ace/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ace/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ace/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ace/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ace/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ace/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ace/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ace/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ace/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ace/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ace/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ace/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ace/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ace/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ace/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ace/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ace/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ace/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ace/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ace/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ace/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ace/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ace/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ace/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ace/releases{/id}",
+ "created_at": "2013-09-26T11:58:10Z",
+ "updated_at": "2013-10-26T12:34:49Z",
+ "pushed_at": "2013-10-26T12:34:48Z",
+ "git_url": "git://github.com/mralexgray/ace.git",
+ "ssh_url": "git@github.com:mralexgray/ace.git",
+ "clone_url": "https://github.com/mralexgray/ace.git",
+ "svn_url": "https://github.com/mralexgray/ace",
+ "homepage": "http://ace.c9.io",
+ "size": 21080,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "JavaScript",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10791045,
+ "name": "ACEView",
+ "full_name": "mralexgray/ACEView",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ACEView",
+ "description": "Use the wonderful ACE editor in your Cocoa applications",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ACEView",
+ "forks_url": "https://api.github.com/repos/mralexgray/ACEView/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ACEView/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ACEView/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ACEView/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ACEView/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ACEView/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ACEView/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ACEView/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ACEView/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ACEView/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ACEView/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ACEView/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ACEView/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ACEView/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ACEView/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ACEView/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ACEView/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ACEView/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ACEView/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ACEView/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ACEView/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ACEView/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ACEView/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ACEView/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ACEView/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ACEView/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ACEView/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ACEView/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ACEView/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ACEView/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ACEView/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ACEView/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ACEView/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ACEView/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ACEView/releases{/id}",
+ "created_at": "2013-06-19T12:15:04Z",
+ "updated_at": "2013-10-30T12:39:24Z",
+ "pushed_at": "2013-10-30T12:39:18Z",
+ "git_url": "git://github.com/mralexgray/ACEView.git",
+ "ssh_url": "git@github.com:mralexgray/ACEView.git",
+ "clone_url": "https://github.com/mralexgray/ACEView.git",
+ "svn_url": "https://github.com/mralexgray/ACEView",
+ "homepage": null,
+ "size": 1661,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13623648,
+ "name": "ActiveLog",
+ "full_name": "mralexgray/ActiveLog",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ActiveLog",
+ "description": "Shut up all logs with active filter.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ActiveLog",
+ "forks_url": "https://api.github.com/repos/mralexgray/ActiveLog/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ActiveLog/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ActiveLog/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ActiveLog/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ActiveLog/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ActiveLog/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ActiveLog/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ActiveLog/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ActiveLog/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ActiveLog/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ActiveLog/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ActiveLog/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ActiveLog/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ActiveLog/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ActiveLog/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ActiveLog/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ActiveLog/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ActiveLog/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ActiveLog/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ActiveLog/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ActiveLog/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ActiveLog/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ActiveLog/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ActiveLog/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ActiveLog/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ActiveLog/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ActiveLog/releases{/id}",
+ "created_at": "2013-10-16T15:52:37Z",
+ "updated_at": "2013-10-16T15:52:37Z",
+ "pushed_at": "2011-07-03T06:28:59Z",
+ "git_url": "git://github.com/mralexgray/ActiveLog.git",
+ "ssh_url": "git@github.com:mralexgray/ActiveLog.git",
+ "clone_url": "https://github.com/mralexgray/ActiveLog.git",
+ "svn_url": "https://github.com/mralexgray/ActiveLog",
+ "homepage": "http://deepitpro.com/en/articles/ActiveLog/info/",
+ "size": 60,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9716210,
+ "name": "adium",
+ "full_name": "mralexgray/adium",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/adium",
+ "description": "Official mirror of hg.adium.im",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/adium",
+ "forks_url": "https://api.github.com/repos/mralexgray/adium/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/adium/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/adium/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/adium/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/adium/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/adium/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/adium/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/adium/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/adium/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/adium/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/adium/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/adium/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/adium/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/adium/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/adium/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/adium/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/adium/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/adium/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/adium/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/adium/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/adium/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/adium/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/adium/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/adium/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/adium/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/adium/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/adium/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/adium/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/adium/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/adium/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/adium/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/adium/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/adium/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/adium/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/adium/releases{/id}",
+ "created_at": "2013-04-27T14:59:33Z",
+ "updated_at": "2013-04-27T14:59:33Z",
+ "pushed_at": "2013-04-26T16:43:53Z",
+ "git_url": "git://github.com/mralexgray/adium.git",
+ "ssh_url": "git@github.com:mralexgray/adium.git",
+ "clone_url": "https://github.com/mralexgray/adium.git",
+ "svn_url": "https://github.com/mralexgray/adium",
+ "homepage": null,
+ "size": 277719,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12752329,
+ "name": "ADLivelyTableView",
+ "full_name": "mralexgray/ADLivelyTableView",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ADLivelyTableView",
+ "description": "Lively UITableView",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ADLivelyTableView",
+ "forks_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/releases{/id}",
+ "created_at": "2013-09-11T09:18:01Z",
+ "updated_at": "2013-09-11T09:18:03Z",
+ "pushed_at": "2012-05-10T10:40:15Z",
+ "git_url": "git://github.com/mralexgray/ADLivelyTableView.git",
+ "ssh_url": "git@github.com:mralexgray/ADLivelyTableView.git",
+ "clone_url": "https://github.com/mralexgray/ADLivelyTableView.git",
+ "svn_url": "https://github.com/mralexgray/ADLivelyTableView",
+ "homepage": "http://applidium.com/en/news/lively_uitableview/",
+ "size": 73,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5697379,
+ "name": "AFIncrementalStore",
+ "full_name": "mralexgray/AFIncrementalStore",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AFIncrementalStore",
+ "description": "Core Data Persistence with AFNetworking, Done Right",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AFIncrementalStore",
+ "forks_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/releases{/id}",
+ "created_at": "2012-09-06T04:20:33Z",
+ "updated_at": "2013-01-12T03:15:29Z",
+ "pushed_at": "2012-09-01T22:46:25Z",
+ "git_url": "git://github.com/mralexgray/AFIncrementalStore.git",
+ "ssh_url": "git@github.com:mralexgray/AFIncrementalStore.git",
+ "clone_url": "https://github.com/mralexgray/AFIncrementalStore.git",
+ "svn_url": "https://github.com/mralexgray/AFIncrementalStore",
+ "homepage": null,
+ "size": 139,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 6969621,
+ "name": "AFNetworking",
+ "full_name": "mralexgray/AFNetworking",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AFNetworking",
+ "description": "A delightful iOS and OS X networking framework",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AFNetworking",
+ "forks_url": "https://api.github.com/repos/mralexgray/AFNetworking/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AFNetworking/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AFNetworking/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AFNetworking/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AFNetworking/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AFNetworking/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AFNetworking/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AFNetworking/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AFNetworking/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AFNetworking/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AFNetworking/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AFNetworking/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AFNetworking/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AFNetworking/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AFNetworking/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AFNetworking/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AFNetworking/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AFNetworking/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AFNetworking/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AFNetworking/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AFNetworking/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AFNetworking/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AFNetworking/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AFNetworking/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AFNetworking/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AFNetworking/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AFNetworking/releases{/id}",
+ "created_at": "2012-12-02T17:00:04Z",
+ "updated_at": "2014-01-24T07:14:33Z",
+ "pushed_at": "2014-01-24T07:14:32Z",
+ "git_url": "git://github.com/mralexgray/AFNetworking.git",
+ "ssh_url": "git@github.com:mralexgray/AFNetworking.git",
+ "clone_url": "https://github.com/mralexgray/AFNetworking.git",
+ "svn_url": "https://github.com/mralexgray/AFNetworking",
+ "homepage": "http://afnetworking.com",
+ "size": 4341,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9485541,
+ "name": "AGNSSplitView",
+ "full_name": "mralexgray/AGNSSplitView",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AGNSSplitView",
+ "description": "Simple NSSplitView additions.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AGNSSplitView",
+ "forks_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/releases{/id}",
+ "created_at": "2013-04-17T00:10:13Z",
+ "updated_at": "2013-04-17T00:10:13Z",
+ "pushed_at": "2013-02-26T00:32:32Z",
+ "git_url": "git://github.com/mralexgray/AGNSSplitView.git",
+ "ssh_url": "git@github.com:mralexgray/AGNSSplitView.git",
+ "clone_url": "https://github.com/mralexgray/AGNSSplitView.git",
+ "svn_url": "https://github.com/mralexgray/AGNSSplitView",
+ "homepage": null,
+ "size": 68,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12767784,
+ "name": "AGScopeBar",
+ "full_name": "mralexgray/AGScopeBar",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AGScopeBar",
+ "description": "Custom scope bar implementation for Cocoa",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AGScopeBar",
+ "forks_url": "https://api.github.com/repos/mralexgray/AGScopeBar/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AGScopeBar/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AGScopeBar/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AGScopeBar/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AGScopeBar/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AGScopeBar/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AGScopeBar/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AGScopeBar/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AGScopeBar/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AGScopeBar/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AGScopeBar/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AGScopeBar/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AGScopeBar/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AGScopeBar/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AGScopeBar/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AGScopeBar/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AGScopeBar/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AGScopeBar/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AGScopeBar/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AGScopeBar/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AGScopeBar/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AGScopeBar/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AGScopeBar/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AGScopeBar/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AGScopeBar/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AGScopeBar/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AGScopeBar/releases{/id}",
+ "created_at": "2013-09-11T21:06:54Z",
+ "updated_at": "2013-09-11T21:06:54Z",
+ "pushed_at": "2013-05-07T03:35:29Z",
+ "git_url": "git://github.com/mralexgray/AGScopeBar.git",
+ "ssh_url": "git@github.com:mralexgray/AGScopeBar.git",
+ "clone_url": "https://github.com/mralexgray/AGScopeBar.git",
+ "svn_url": "https://github.com/mralexgray/AGScopeBar",
+ "homepage": null,
+ "size": 64,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9227846,
+ "name": "AHContentBrowser",
+ "full_name": "mralexgray/AHContentBrowser",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AHContentBrowser",
+ "description": "A Mac only webview that loads a fast readable version of the website if available.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AHContentBrowser",
+ "forks_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/releases{/id}",
+ "created_at": "2013-04-04T20:56:16Z",
+ "updated_at": "2013-04-04T20:56:16Z",
+ "pushed_at": "2013-03-13T17:38:23Z",
+ "git_url": "git://github.com/mralexgray/AHContentBrowser.git",
+ "ssh_url": "git@github.com:mralexgray/AHContentBrowser.git",
+ "clone_url": "https://github.com/mralexgray/AHContentBrowser.git",
+ "svn_url": "https://github.com/mralexgray/AHContentBrowser",
+ "homepage": "",
+ "size": 223,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9167473,
+ "name": "AHLayout",
+ "full_name": "mralexgray/AHLayout",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AHLayout",
+ "description": "AHLayout",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AHLayout",
+ "forks_url": "https://api.github.com/repos/mralexgray/AHLayout/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AHLayout/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AHLayout/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AHLayout/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AHLayout/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AHLayout/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AHLayout/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AHLayout/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AHLayout/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AHLayout/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AHLayout/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AHLayout/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AHLayout/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AHLayout/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AHLayout/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AHLayout/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AHLayout/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AHLayout/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AHLayout/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AHLayout/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AHLayout/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AHLayout/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AHLayout/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AHLayout/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AHLayout/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AHLayout/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AHLayout/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AHLayout/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AHLayout/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AHLayout/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AHLayout/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AHLayout/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AHLayout/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AHLayout/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AHLayout/releases{/id}",
+ "created_at": "2013-04-02T10:10:30Z",
+ "updated_at": "2013-07-08T02:31:17Z",
+ "pushed_at": "2013-07-08T02:31:14Z",
+ "git_url": "git://github.com/mralexgray/AHLayout.git",
+ "ssh_url": "git@github.com:mralexgray/AHLayout.git",
+ "clone_url": "https://github.com/mralexgray/AHLayout.git",
+ "svn_url": "https://github.com/mralexgray/AHLayout",
+ "homepage": null,
+ "size": 359,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 18450201,
+ "name": "Airmail-Plug-In-Framework",
+ "full_name": "mralexgray/Airmail-Plug-In-Framework",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework",
+ "description": "",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework",
+ "forks_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/releases{/id}",
+ "created_at": "2014-04-04T19:33:54Z",
+ "updated_at": "2014-04-04T19:33:54Z",
+ "pushed_at": "2014-03-27T15:42:19Z",
+ "git_url": "git://github.com/mralexgray/Airmail-Plug-In-Framework.git",
+ "ssh_url": "git@github.com:mralexgray/Airmail-Plug-In-Framework.git",
+ "clone_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework.git",
+ "svn_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework",
+ "homepage": null,
+ "size": 888,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5203219,
+ "name": "AJS-iTunes-API",
+ "full_name": "mralexgray/AJS-iTunes-API",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AJS-iTunes-API",
+ "description": "Cocoa wrapper for the iTunes search API - for iOS and Mac OSX projects",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API",
+ "forks_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/releases{/id}",
+ "created_at": "2012-07-27T10:20:58Z",
+ "updated_at": "2013-01-11T11:00:05Z",
+ "pushed_at": "2011-10-30T22:26:48Z",
+ "git_url": "git://github.com/mralexgray/AJS-iTunes-API.git",
+ "ssh_url": "git@github.com:mralexgray/AJS-iTunes-API.git",
+ "clone_url": "https://github.com/mralexgray/AJS-iTunes-API.git",
+ "svn_url": "https://github.com/mralexgray/AJS-iTunes-API",
+ "homepage": "",
+ "size": 103,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10093801,
+ "name": "Alcatraz",
+ "full_name": "mralexgray/Alcatraz",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Alcatraz",
+ "description": "The most awesome (and only) Xcode package manager!",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Alcatraz",
+ "forks_url": "https://api.github.com/repos/mralexgray/Alcatraz/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Alcatraz/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Alcatraz/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Alcatraz/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Alcatraz/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Alcatraz/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Alcatraz/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Alcatraz/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Alcatraz/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Alcatraz/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Alcatraz/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Alcatraz/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Alcatraz/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Alcatraz/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Alcatraz/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Alcatraz/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Alcatraz/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Alcatraz/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Alcatraz/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Alcatraz/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Alcatraz/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Alcatraz/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Alcatraz/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Alcatraz/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Alcatraz/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Alcatraz/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Alcatraz/releases{/id}",
+ "created_at": "2013-05-16T04:41:13Z",
+ "updated_at": "2014-03-19T20:38:35Z",
+ "pushed_at": "2014-03-19T12:50:37Z",
+ "git_url": "git://github.com/mralexgray/Alcatraz.git",
+ "ssh_url": "git@github.com:mralexgray/Alcatraz.git",
+ "clone_url": "https://github.com/mralexgray/Alcatraz.git",
+ "svn_url": "https://github.com/mralexgray/Alcatraz",
+ "homepage": "mneorr.github.com/Alcatraz",
+ "size": 3668,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12916552,
+ "name": "alcatraz-packages",
+ "full_name": "mralexgray/alcatraz-packages",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/alcatraz-packages",
+ "description": "Package list repository for Alcatraz",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/alcatraz-packages",
+ "forks_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/releases{/id}",
+ "created_at": "2013-09-18T07:15:24Z",
+ "updated_at": "2013-09-18T07:15:25Z",
+ "pushed_at": "2013-09-09T07:51:48Z",
+ "git_url": "git://github.com/mralexgray/alcatraz-packages.git",
+ "ssh_url": "git@github.com:mralexgray/alcatraz-packages.git",
+ "clone_url": "https://github.com/mralexgray/alcatraz-packages.git",
+ "svn_url": "https://github.com/mralexgray/alcatraz-packages",
+ "homepage": "mneorr.github.com/Alcatraz",
+ "size": 482,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Ruby",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10476467,
+ "name": "Alfred-Google-Translate",
+ "full_name": "mralexgray/Alfred-Google-Translate",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Alfred-Google-Translate",
+ "description": "Extension for Alfred that will do a Google translate for you",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate",
+ "forks_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/releases{/id}",
+ "created_at": "2013-06-04T10:45:10Z",
+ "updated_at": "2013-06-04T10:45:10Z",
+ "pushed_at": "2013-01-12T19:39:03Z",
+ "git_url": "git://github.com/mralexgray/Alfred-Google-Translate.git",
+ "ssh_url": "git@github.com:mralexgray/Alfred-Google-Translate.git",
+ "clone_url": "https://github.com/mralexgray/Alfred-Google-Translate.git",
+ "svn_url": "https://github.com/mralexgray/Alfred-Google-Translate",
+ "homepage": null,
+ "size": 103,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Shell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5524019,
+ "name": "Amber",
+ "full_name": "mralexgray/Amber",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Amber",
+ "description": "Fork of the difficult-to-deal-with Amber.framework",
+ "fork": false,
+ "url": "https://api.github.com/repos/mralexgray/Amber",
+ "forks_url": "https://api.github.com/repos/mralexgray/Amber/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Amber/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Amber/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Amber/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Amber/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Amber/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Amber/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Amber/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Amber/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Amber/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Amber/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Amber/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Amber/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Amber/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Amber/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Amber/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Amber/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Amber/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Amber/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Amber/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Amber/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Amber/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Amber/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Amber/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Amber/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Amber/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Amber/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Amber/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Amber/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Amber/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Amber/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Amber/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Amber/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Amber/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Amber/releases{/id}",
+ "created_at": "2012-08-23T10:38:24Z",
+ "updated_at": "2013-01-11T22:25:35Z",
+ "pushed_at": "2012-08-23T10:38:25Z",
+ "git_url": "git://github.com/mralexgray/Amber.git",
+ "ssh_url": "git@github.com:mralexgray/Amber.git",
+ "clone_url": "https://github.com/mralexgray/Amber.git",
+ "svn_url": "https://github.com/mralexgray/Amber",
+ "homepage": null,
+ "size": 48,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": true,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10809060,
+ "name": "Amethyst",
+ "full_name": "mralexgray/Amethyst",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Amethyst",
+ "description": "Tiling window manager for OS X.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Amethyst",
+ "forks_url": "https://api.github.com/repos/mralexgray/Amethyst/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Amethyst/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Amethyst/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Amethyst/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Amethyst/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Amethyst/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Amethyst/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Amethyst/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Amethyst/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Amethyst/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Amethyst/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Amethyst/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Amethyst/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Amethyst/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Amethyst/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Amethyst/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Amethyst/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Amethyst/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Amethyst/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Amethyst/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Amethyst/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Amethyst/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Amethyst/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Amethyst/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Amethyst/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Amethyst/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Amethyst/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Amethyst/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Amethyst/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Amethyst/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Amethyst/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Amethyst/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Amethyst/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Amethyst/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Amethyst/releases{/id}",
+ "created_at": "2013-06-20T00:34:22Z",
+ "updated_at": "2013-06-20T00:34:22Z",
+ "pushed_at": "2013-06-18T02:54:11Z",
+ "git_url": "git://github.com/mralexgray/Amethyst.git",
+ "ssh_url": "git@github.com:mralexgray/Amethyst.git",
+ "clone_url": "https://github.com/mralexgray/Amethyst.git",
+ "svn_url": "https://github.com/mralexgray/Amethyst",
+ "homepage": "http://ianyh.github.io/Amethyst/",
+ "size": 12623,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 3684286,
+ "name": "Animated-Paths",
+ "full_name": "mralexgray/Animated-Paths",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Animated-Paths",
+ "description": "Demo project: Animating the drawing of a CGPath with CAShapeLayer.strokeEnd",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Animated-Paths",
+ "forks_url": "https://api.github.com/repos/mralexgray/Animated-Paths/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Animated-Paths/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Animated-Paths/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Animated-Paths/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Animated-Paths/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Animated-Paths/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Animated-Paths/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Animated-Paths/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Animated-Paths/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Animated-Paths/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Animated-Paths/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Animated-Paths/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Animated-Paths/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Animated-Paths/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Animated-Paths/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Animated-Paths/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Animated-Paths/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Animated-Paths/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Animated-Paths/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Animated-Paths/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Animated-Paths/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Animated-Paths/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Animated-Paths/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Animated-Paths/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Animated-Paths/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Animated-Paths/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Animated-Paths/releases{/id}",
+ "created_at": "2012-03-11T02:56:38Z",
+ "updated_at": "2013-01-08T04:12:21Z",
+ "pushed_at": "2010-12-30T20:56:51Z",
+ "git_url": "git://github.com/mralexgray/Animated-Paths.git",
+ "ssh_url": "git@github.com:mralexgray/Animated-Paths.git",
+ "clone_url": "https://github.com/mralexgray/Animated-Paths.git",
+ "svn_url": "https://github.com/mralexgray/Animated-Paths",
+ "homepage": "http://oleb.net/blog/2010/12/animating-drawing-of-cgpath-with-cashapelayer/",
+ "size": 411,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 16662874,
+ "name": "AnsiLove.framework",
+ "full_name": "mralexgray/AnsiLove.framework",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AnsiLove.framework",
+ "description": "Cocoa Framework for rendering ANSi / ASCII art",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AnsiLove.framework",
+ "forks_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/releases{/id}",
+ "created_at": "2014-02-09T08:30:27Z",
+ "updated_at": "2014-02-09T08:30:32Z",
+ "pushed_at": "2013-10-04T14:08:38Z",
+ "git_url": "git://github.com/mralexgray/AnsiLove.framework.git",
+ "ssh_url": "git@github.com:mralexgray/AnsiLove.framework.git",
+ "clone_url": "https://github.com/mralexgray/AnsiLove.framework.git",
+ "svn_url": "https://github.com/mralexgray/AnsiLove.framework",
+ "homepage": "http://byteproject.net",
+ "size": 3780,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "M",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5189563,
+ "name": "ANTrackBar",
+ "full_name": "mralexgray/ANTrackBar",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ANTrackBar",
+ "description": "An easy-to-use Cocoa seek bar with a pleasing appearance",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ANTrackBar",
+ "forks_url": "https://api.github.com/repos/mralexgray/ANTrackBar/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ANTrackBar/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ANTrackBar/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ANTrackBar/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ANTrackBar/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ANTrackBar/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ANTrackBar/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ANTrackBar/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ANTrackBar/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ANTrackBar/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ANTrackBar/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ANTrackBar/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ANTrackBar/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ANTrackBar/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ANTrackBar/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ANTrackBar/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ANTrackBar/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ANTrackBar/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ANTrackBar/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ANTrackBar/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ANTrackBar/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ANTrackBar/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ANTrackBar/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ANTrackBar/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ANTrackBar/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ANTrackBar/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ANTrackBar/releases{/id}",
+ "created_at": "2012-07-26T08:17:22Z",
+ "updated_at": "2013-01-11T10:29:56Z",
+ "pushed_at": "2012-03-09T01:40:02Z",
+ "git_url": "git://github.com/mralexgray/ANTrackBar.git",
+ "ssh_url": "git@github.com:mralexgray/ANTrackBar.git",
+ "clone_url": "https://github.com/mralexgray/ANTrackBar.git",
+ "svn_url": "https://github.com/mralexgray/ANTrackBar",
+ "homepage": "",
+ "size": 94,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 16240152,
+ "name": "AOP-in-Objective-C",
+ "full_name": "mralexgray/AOP-in-Objective-C",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AOP-in-Objective-C",
+ "description": "An NSProxy based library for easily enabling AOP like functionality in Objective-C.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C",
+ "forks_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/releases{/id}",
+ "created_at": "2014-01-25T21:18:04Z",
+ "updated_at": "2014-02-12T16:23:21Z",
+ "pushed_at": "2014-02-12T16:23:20Z",
+ "git_url": "git://github.com/mralexgray/AOP-in-Objective-C.git",
+ "ssh_url": "git@github.com:mralexgray/AOP-in-Objective-C.git",
+ "clone_url": "https://github.com/mralexgray/AOP-in-Objective-C.git",
+ "svn_url": "https://github.com/mralexgray/AOP-in-Objective-C",
+ "homepage": "http://innoli.hu/en/opensource/",
+ "size": 340,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 1,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 1,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "travis-coveralls",
+ "master_branch": "travis-coveralls"
+ },
+ {
+ "id": 13141936,
+ "name": "Apaxy",
+ "full_name": "mralexgray/Apaxy",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Apaxy",
+ "description": "A simple, customisable theme for your Apache directory listing.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Apaxy",
+ "forks_url": "https://api.github.com/repos/mralexgray/Apaxy/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Apaxy/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Apaxy/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Apaxy/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Apaxy/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Apaxy/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Apaxy/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Apaxy/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Apaxy/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Apaxy/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Apaxy/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Apaxy/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Apaxy/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Apaxy/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Apaxy/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Apaxy/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Apaxy/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Apaxy/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Apaxy/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Apaxy/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Apaxy/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Apaxy/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Apaxy/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Apaxy/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Apaxy/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Apaxy/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Apaxy/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Apaxy/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Apaxy/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Apaxy/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Apaxy/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Apaxy/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Apaxy/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Apaxy/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Apaxy/releases{/id}",
+ "created_at": "2013-09-27T05:05:35Z",
+ "updated_at": "2013-09-27T05:05:36Z",
+ "pushed_at": "2013-08-02T16:01:32Z",
+ "git_url": "git://github.com/mralexgray/Apaxy.git",
+ "ssh_url": "git@github.com:mralexgray/Apaxy.git",
+ "clone_url": "https://github.com/mralexgray/Apaxy.git",
+ "svn_url": "https://github.com/mralexgray/Apaxy",
+ "homepage": null,
+ "size": 113,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "CSS",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10048098,
+ "name": "appledoc",
+ "full_name": "mralexgray/appledoc",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/appledoc",
+ "description": "Objective-c code Apple style documentation set generator.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/appledoc",
+ "forks_url": "https://api.github.com/repos/mralexgray/appledoc/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/appledoc/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/appledoc/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/appledoc/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/appledoc/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/appledoc/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/appledoc/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/appledoc/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/appledoc/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/appledoc/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/appledoc/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/appledoc/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/appledoc/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/appledoc/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/appledoc/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/appledoc/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/appledoc/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/appledoc/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/appledoc/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/appledoc/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/appledoc/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/appledoc/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/appledoc/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/appledoc/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/appledoc/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/appledoc/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/appledoc/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/appledoc/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/appledoc/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/appledoc/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/appledoc/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/appledoc/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/appledoc/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/appledoc/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/appledoc/releases{/id}",
+ "created_at": "2013-05-14T05:45:44Z",
+ "updated_at": "2014-02-09T08:14:42Z",
+ "pushed_at": "2014-02-09T08:14:42Z",
+ "git_url": "git://github.com/mralexgray/appledoc.git",
+ "ssh_url": "git@github.com:mralexgray/appledoc.git",
+ "clone_url": "https://github.com/mralexgray/appledoc.git",
+ "svn_url": "https://github.com/mralexgray/appledoc",
+ "homepage": "http://gentlebytes.com",
+ "size": 10336,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": false,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 16160992,
+ "name": "Appstore-Through-Terminal",
+ "full_name": "mralexgray/Appstore-Through-Terminal",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Appstore-Through-Terminal",
+ "description": "A simple debian package, made for iPhone, to open the iOS AppStore through terminal. Simple. Slightly usless. My work as a beginner.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal",
+ "forks_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/releases{/id}",
+ "created_at": "2014-01-23T03:21:34Z",
+ "updated_at": "2014-01-23T03:21:34Z",
+ "pushed_at": "2011-12-21T06:40:25Z",
+ "git_url": "git://github.com/mralexgray/Appstore-Through-Terminal.git",
+ "ssh_url": "git@github.com:mralexgray/Appstore-Through-Terminal.git",
+ "clone_url": "https://github.com/mralexgray/Appstore-Through-Terminal.git",
+ "svn_url": "https://github.com/mralexgray/Appstore-Through-Terminal",
+ "homepage": "http://getagripon.com/tillie/projects.html",
+ "size": 104,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Shell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13709216,
+ "name": "appweb-4",
+ "full_name": "mralexgray/appweb-4",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/appweb-4",
+ "description": "Appweb Embeddable Web Server 4",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/appweb-4",
+ "forks_url": "https://api.github.com/repos/mralexgray/appweb-4/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/appweb-4/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/appweb-4/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/appweb-4/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/appweb-4/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/appweb-4/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/appweb-4/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/appweb-4/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/appweb-4/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/appweb-4/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/appweb-4/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/appweb-4/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/appweb-4/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/appweb-4/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/appweb-4/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/appweb-4/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/appweb-4/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/appweb-4/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/appweb-4/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/appweb-4/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/appweb-4/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/appweb-4/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/appweb-4/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/appweb-4/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/appweb-4/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/appweb-4/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/appweb-4/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/appweb-4/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/appweb-4/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/appweb-4/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/appweb-4/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/appweb-4/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/appweb-4/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/appweb-4/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/appweb-4/releases{/id}",
+ "created_at": "2013-10-19T21:36:10Z",
+ "updated_at": "2013-10-19T21:36:11Z",
+ "pushed_at": "2013-10-19T00:35:06Z",
+ "git_url": "git://github.com/mralexgray/appweb-4.git",
+ "ssh_url": "git@github.com:mralexgray/appweb-4.git",
+ "clone_url": "https://github.com/mralexgray/appweb-4.git",
+ "svn_url": "https://github.com/mralexgray/appweb-4",
+ "homepage": "http://appwebserver.org",
+ "size": 58244,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12501983,
+ "name": "arbor",
+ "full_name": "mralexgray/arbor",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/arbor",
+ "description": "a graph visualization library using web workers and jQuery",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/arbor",
+ "forks_url": "https://api.github.com/repos/mralexgray/arbor/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/arbor/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/arbor/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/arbor/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/arbor/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/arbor/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/arbor/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/arbor/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/arbor/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/arbor/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/arbor/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/arbor/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/arbor/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/arbor/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/arbor/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/arbor/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/arbor/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/arbor/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/arbor/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/arbor/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/arbor/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/arbor/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/arbor/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/arbor/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/arbor/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/arbor/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/arbor/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/arbor/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/arbor/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/arbor/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/arbor/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/arbor/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/arbor/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/arbor/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/arbor/releases{/id}",
+ "created_at": "2013-08-31T07:07:05Z",
+ "updated_at": "2013-08-31T07:07:06Z",
+ "pushed_at": "2012-05-28T00:47:58Z",
+ "git_url": "git://github.com/mralexgray/arbor.git",
+ "ssh_url": "git@github.com:mralexgray/arbor.git",
+ "clone_url": "https://github.com/mralexgray/arbor.git",
+ "svn_url": "https://github.com/mralexgray/arbor",
+ "homepage": "http://arborjs.org",
+ "size": 237,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "JavaScript",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13537888,
+ "name": "Archimedes",
+ "full_name": "mralexgray/Archimedes",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Archimedes",
+ "description": "Geometry functions for Cocoa and Cocoa Touch",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Archimedes",
+ "forks_url": "https://api.github.com/repos/mralexgray/Archimedes/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Archimedes/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Archimedes/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Archimedes/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Archimedes/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Archimedes/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Archimedes/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Archimedes/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Archimedes/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Archimedes/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Archimedes/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Archimedes/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Archimedes/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Archimedes/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Archimedes/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Archimedes/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Archimedes/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Archimedes/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Archimedes/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Archimedes/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Archimedes/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Archimedes/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Archimedes/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Archimedes/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Archimedes/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Archimedes/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Archimedes/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Archimedes/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Archimedes/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Archimedes/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Archimedes/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Archimedes/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Archimedes/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Archimedes/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Archimedes/releases{/id}",
+ "created_at": "2013-10-13T11:08:19Z",
+ "updated_at": "2014-04-06T00:41:21Z",
+ "pushed_at": "2014-04-06T00:41:20Z",
+ "git_url": "git://github.com/mralexgray/Archimedes.git",
+ "ssh_url": "git@github.com:mralexgray/Archimedes.git",
+ "clone_url": "https://github.com/mralexgray/Archimedes.git",
+ "svn_url": "https://github.com/mralexgray/Archimedes",
+ "homepage": null,
+ "size": 217,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5260205,
+ "name": "arrsync",
+ "full_name": "mralexgray/arrsync",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/arrsync",
+ "description": "",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/arrsync",
+ "forks_url": "https://api.github.com/repos/mralexgray/arrsync/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/arrsync/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/arrsync/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/arrsync/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/arrsync/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/arrsync/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/arrsync/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/arrsync/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/arrsync/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/arrsync/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/arrsync/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/arrsync/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/arrsync/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/arrsync/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/arrsync/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/arrsync/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/arrsync/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/arrsync/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/arrsync/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/arrsync/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/arrsync/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/arrsync/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/arrsync/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/arrsync/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/arrsync/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/arrsync/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/arrsync/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/arrsync/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/arrsync/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/arrsync/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/arrsync/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/arrsync/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/arrsync/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/arrsync/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/arrsync/releases{/id}",
+ "created_at": "2012-08-01T14:21:49Z",
+ "updated_at": "2013-01-11T13:12:21Z",
+ "pushed_at": "2011-05-09T18:56:56Z",
+ "git_url": "git://github.com/mralexgray/arrsync.git",
+ "ssh_url": "git@github.com:mralexgray/arrsync.git",
+ "clone_url": "https://github.com/mralexgray/arrsync.git",
+ "svn_url": "https://github.com/mralexgray/arrsync",
+ "homepage": "",
+ "size": 194,
+ "stargazers_count": 2,
+ "watchers_count": 2,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 2,
+ "default_branch": "master",
+ "master_branch": "master"
+ }
+]
+} \ No newline at end of file
diff --git a/libparc/parc/algol/test/test_parc_ArrayList.c b/libparc/parc/algol/test/test_parc_ArrayList.c
new file mode 100755
index 00000000..9e387a28
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_ArrayList.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_ArrayList.c"
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(PARC_ArrayList)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_ArrayList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_ArrayList)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Add);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_AddAll);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Destroy);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_CustomDestroyer);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Equals_Contract_Deep);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_FromInitialCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_New);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_IsEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Add)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ parcArrayList_Add(array, 0);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_AddAll)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ void *elements[] = {
+ strdup("a"),
+ strdup("b"),
+ strdup("c"),
+ };
+
+ parcArrayList_AddAll(array, elements, 3);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Copy)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *copy = parcArrayList_Copy(array);
+ assertTrue(parcArrayList_Equals(array, copy), "Expected arrays to be equal.");
+
+ parcArrayList_Destroy(&copy);
+ parcArrayList_Destroy(&array);
+}
+
+static void
+testCustomDestroyer(void **bufferVoidPtr)
+{
+ PARCBuffer **bufferPtr = (PARCBuffer **) bufferVoidPtr;
+ parcBuffer_Release(bufferPtr);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_CustomDestroyer)
+{
+ size_t before = parcMemory_Outstanding();
+
+ PARCArrayList *array = parcArrayList_Create(testCustomDestroyer);
+ PARCBuffer *buffer = parcBuffer_Allocate(20);
+ parcArrayList_Add(array, parcBuffer_Acquire(buffer));
+ parcBuffer_Release(&buffer);
+ parcArrayList_Destroy(&array);
+
+ size_t after = parcMemory_Outstanding();
+
+ assertTrue(before == after, "Memory imbalance after using custom destroy, expected %zu got %zu", before, after);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Destroy)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ parcArrayList_Destroy(&array);
+ assertNull(array, "Expected null.");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Empty)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ PARCArrayList *b = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, b), "Equal values were expected to be equal");
+
+ parcArrayList_Destroy(&a);
+ parcArrayList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Same)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, a), "Expected the same array list to be equal to itself.");
+
+ parcArrayList_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Contract)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create(NULL);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create(NULL);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create(NULL);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+static bool
+stringEquals(void *x, void *y)
+{
+ return strcmp((char *) x, (char *) y) == 0;
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Contract_Deep)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u2, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+LONGBOW_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_Empty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ size_t expected = 4;
+ _ensureRemaining(array, expected);
+
+ size_t actual = _remaining(array);
+
+ assertTrue(actual >= expected, "Expected >= %zd, actual=%zd", expected, actual);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_NonEmpty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t expected = 5;
+ _ensureRemaining(array, expected);
+
+ size_t actual = _remaining(array);
+
+ assertTrue(actual >= expected, "Expected >= %zd, actual=%zd", expected, actual);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_FromInitialCapacity)
+{
+ PARCArrayList *array = parcArrayList_Create_Capacity(NULL, parcArrayList_StdlibFreeFunction, 10);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(0 == actual, "Expected=%d, actual=%zu", 0, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Get)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ char *expected = strdup("Hello World");
+ parcArrayList_Add(array, expected);
+
+ char *actual = parcArrayList_Get(array, 0);
+
+ assertTrue(expected == actual, "Expected=%p, actual=%p", (void *) expected, (void *) actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_New)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ size_t size = parcArrayList_Size(array);
+ assertTrue(0 == size, "Expected %d actual=%zu", 0, size);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Size)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t size = parcArrayList_Size(array);
+ assertTrue(1 == size, "Expected %d actual=%zu", 1, size);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_IsEmpty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ assertTrue(parcArrayList_IsEmpty(array), "Expected a new array to be empty.");
+
+ parcArrayList_Add(array, 0);
+ assertFalse(parcArrayList_IsEmpty(array), "Expected an array with more than zero elements to be empty.");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 1, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 3, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 2, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Empty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_InsertAtIndex(array, 0, (void *) 3);
+
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_First)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_InsertAtIndex(array, 0, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 2, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 1, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Last)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 2, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 2, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 3, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 0);
+
+ assertTrue(removedElement == a, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 1);
+
+ assertTrue(removedElement == b, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 2);
+
+ assertTrue(removedElement == c, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 0);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 1);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 2);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_Empty);
+ LONGBOW_RUN_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_NonEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, PARC_ArrayList_InsertAtIndex_OutOfCapacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ longBowTestCase_SetClipBoardData(testCase, array);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+ parcArrayList_Destroy(&array);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARC_ArrayList_InsertAtIndex_OutOfCapacity, .event = &LongBowAssertEvent)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+
+ parcArrayList_InsertAtIndex(array, 200, (void *) 3);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_ArrayList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_AtomicInteger.c b/libparc/parc/algol/test/test_parc_AtomicInteger.c
new file mode 100644
index 00000000..9bd1b99a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_AtomicInteger.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_AtomicInteger.c"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_AtomicInteger)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Threaded);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_AtomicInteger)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_AtomicInteger)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint32Increment);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint32Decrement);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint64Increment);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint64Decrement);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint32Increment)
+{
+ uint32_t value = 0;
+ parcAtomicInteger_Uint32Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %u", value);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint32Decrement)
+{
+ uint32_t value = 0;
+ parcAtomicInteger_Uint32Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %u", value);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint64Increment)
+{
+ uint64_t value = 0;
+ parcAtomicInteger_Uint64Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %" PRIu64 "", value);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint64Decrement)
+{
+ uint64_t value = 0;
+ parcAtomicInteger_Uint64Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %" PRIu64 "", value);
+}
+
+LONGBOW_TEST_FIXTURE(Threaded)
+{
+ LONGBOW_RUN_TEST_CASE(Threaded, collaborative);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Threaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Threaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void *
+collaborator_A(void *data)
+{
+ uint32_t *valuePointer = (uint32_t *) data;
+ uint32_t contribution = 0;
+ while (*valuePointer < 1000000) {
+ parcAtomicInteger_Uint32Increment(valuePointer);
+ contribution++;
+ }
+ printf("A contribution %d\n", contribution);
+ pthread_exit((void *) NULL);
+}
+
+static void *
+collaborator_B(void *data)
+{
+ uint32_t *valuePointer = (uint32_t *) data;
+
+ uint32_t contribution = 0;
+ while (*valuePointer < 1000000) {
+ parcAtomicInteger_Uint32Increment(valuePointer);
+ contribution++;
+ }
+
+ printf("B contribution %d\n", contribution);
+ pthread_exit((void *) NULL);
+}
+
+LONGBOW_TEST_CASE(Threaded, collaborative)
+{
+ uint32_t value = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+
+ pthread_create(&thread_A, NULL, collaborator_A, &value);
+ pthread_create(&thread_B, NULL, collaborator_B, &value);
+
+ pthread_join(thread_A, NULL);
+ pthread_join(thread_B, NULL);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_AtomicInteger);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Base64.c b/libparc/parc/algol/test/test_parc_Base64.c
new file mode 100755
index 00000000..4509ded3
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Base64.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Base64.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Base64)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Base64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Base64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Decode_Linefeeds);
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Encode);
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Encode_Binary);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static struct testvector_s {
+ char *plaintext;
+ char *encoded;
+} testvector[] = {
+ // Test vectors from RFC 4648
+ { .plaintext = "", .encoded = "" },
+ { .plaintext = "f", .encoded = "Zg==" },
+ { .plaintext = "fo", .encoded = "Zm8=" },
+ { .plaintext = "foo", .encoded = "Zm9v" },
+ { .plaintext = "foob", .encoded = "Zm9vYg==" },
+ { .plaintext = "fooba", .encoded = "Zm9vYmE=" },
+ { .plaintext = "foobar", .encoded = "Zm9vYmFy" },
+ { .plaintext = NULL, .encoded = NULL }
+};
+
+LONGBOW_TEST_CASE(Global, parcBase64_Decode)
+{
+ int i = 0;
+ while (testvector[i].plaintext != NULL) {
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ parcBufferComposer_PutString(input, testvector[i].encoded);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+ parcBufferComposer_PutString(truth, testvector[i].plaintext);
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ parcBase64_Decode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ i++;
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcBase64_Decode_Linefeeds)
+{
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ char plaintext[] = "It was a dark and stormy night, and all through the code not bit was stirring.\x0A";
+ char encoded_with_crlf[] = "SXQg" "\x0D\x0A" "d2FzIGEgZGFyayBhbmQgc3Rvcm15IG5pZ2h0LCBhbmQgYWxsIHRocm91Z2gg" "\x0D\x0A" "dGhlIGNvZGUgbm90IGJpdCB3YXMgc3RpcnJpbmcuCg==";
+
+ parcBufferComposer_PutString(input, encoded_with_crlf);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+
+ parcBufferComposer_PutString(truth, plaintext);
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ parcBase64_Decode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcBase64_Encode)
+{
+ int i = 0;
+ while (testvector[i].plaintext != NULL) {
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ parcBufferComposer_PutString(input, testvector[i].plaintext);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+ parcBufferComposer_PutString(truth, testvector[i].encoded);
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ parcBase64_Encode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ i++;
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcBase64_Encode_Binary)
+{
+ uint8_t zero[] = { 0 };
+
+ // 1 2 3 4 5 6 7
+ char *truthvector[] = { "AA==", "AAA=", "AAAA", "AAAAAA==", "AAAAAAA=", "AAAAAAAA", "AAAAAAAAAA==" };
+
+ for (int i = 0; i < sizeof(truthvector) / sizeof(truthvector[0]); i++) {
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ parcBufferComposer_PutArray(truth, (uint8_t *) truthvector[i], strlen(truthvector[i]));
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ // just keep apending a zero to make it longer
+ parcBuffer_SetLimit(parcBufferComposer_GetBuffer(input), parcBuffer_Capacity(parcBufferComposer_GetBuffer(input)));
+ parcBuffer_SetPosition(parcBufferComposer_GetBuffer(input), i);
+ parcBufferComposer_PutArray(input, zero, 1);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+
+ parcBase64_Encode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_0);
+ LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_1);
+ LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_2);
+ LONGBOW_RUN_TEST_CASE(Local, decode_invalid);
+ LONGBOW_RUN_TEST_CASE(Local, decode_1);
+ LONGBOW_RUN_TEST_CASE(Local, decode_2);
+ LONGBOW_RUN_TEST_CASE(Local, decode_3);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * This will encode "foo"
+ */
+LONGBOW_TEST_CASE(Local, encodeWithPad_0)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "foobar";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "Zm9v");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ _encodeWithPad(output, input, 0);
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+/**
+ * This will encode "fo" because we tell it there's 1 pad byte
+ */
+LONGBOW_TEST_CASE(Local, encodeWithPad_1)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "foobar";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "Zm8=");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ _encodeWithPad(output, input, 1);
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+/**
+ * This will encode "f" because we tell it there's 2 pad byte
+ */
+LONGBOW_TEST_CASE(Local, encodeWithPad_2)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "foobar";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "Zg==");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ _encodeWithPad(output, input, 2);
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+
+LONGBOW_TEST_CASE(Local, decode_1)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "Zg==";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "f");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ bool success = _decode(output, input);
+ assertTrue(success, "Valid base64 failed decode");
+
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Local, decode_2)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "Zm8=";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "fo");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ bool success = _decode(output, input);
+ assertTrue(success, "Valid base64 failed decode");
+
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Local, decode_3)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "Zm9v";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "foo");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ bool success = _decode(output, input);
+ assertTrue(success, "Valid base64 failed decode");
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Local, decode_invalid)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "@@@@";
+
+ bool success = _decode(output, input);
+ assertFalse(success, "Invalid base64 somehow decoded");
+
+ parcBufferComposer_Release(&output);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Base64);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_BitVector.c b/libparc/parc/algol/test/test_parc_BitVector.c
new file mode 100755
index 00000000..9a4d0806
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_BitVector.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_BitVector.c"
+
+#include <stdio.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <limits.h>
+
+LONGBOW_TEST_RUNNER(parc_BitVector)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_BitVector)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_BitVector)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Create_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_SetClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_SetVector);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Reset);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_ClearVector);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_NextBitSet);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Get);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Contains);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Set);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_And);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Or);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Shift);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Create_Release)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ PARCBitVector *reference = parcBitVector;
+ parcBitVector_Acquire(reference);
+ parcBitVector_Release(&parcBitVector);
+ parcBitVector_Release(&reference);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Set)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ parcBitVector_Set(parcBitVector, 0);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "Expect number of bits set to be 1");
+ assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0");
+ assertTrue(parcBitVector->bitLength == 8, "Expect the bitLength to be 8");
+ assertTrue(parcBitVector->bitArray[0] == (uint8_t) 1, "Expect the bitArray as a unsigned char to be = 1");
+
+ parcBitVector_Set(parcBitVector, 7);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "Expect number of bits set to be 2");
+ assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0");
+ assertTrue(parcBitVector->bitLength == 8, "Expect the bitLength to be 8");
+ assertTrue(parcBitVector->bitArray[0] == (uint8_t) 0x81, "Expect the bitArray as a unsigned char to be = 0x81");
+
+ parcBitVector_Set(parcBitVector, 8);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 3, "Expect number of bits set to be 3");
+ assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0");
+ assertTrue(parcBitVector->bitLength == 16, "Expect the bitLength to be 16");
+ assertTrue(parcBitVector->bitArray[0] == (uint8_t) 0x81, "Expect the bitArray as a unsigned char to be = 0x81");
+ assertTrue(parcBitVector->bitArray[1] == (uint8_t) 0x1, "Expect the bitArray as a unsigned char to be = 0x1");
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_And)
+{
+ PARCBitVector *vector1 = parcBitVector_Create();
+ PARCBitVector *vector2 = parcBitVector_Create();
+
+ parcBitVector_Set(vector1, 1);
+ parcBitVector_Set(vector1, 2);
+ parcBitVector_Set(vector1, 10);
+ parcBitVector_Set(vector2, 2);
+ parcBitVector_Set(vector2, 1);
+ parcBitVector_Set(vector2, 20);
+
+ PARCBitVector *result = parcBitVector_And(vector1, vector2);
+
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 2, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_And(vector1, NULL);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_And(NULL, vector2);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_And(NULL, NULL);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ parcBitVector_Release(&vector1);
+ parcBitVector_Release(&vector2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Or)
+{
+ PARCBitVector *vector1 = parcBitVector_Create();
+ PARCBitVector *vector2 = parcBitVector_Create();
+
+ parcBitVector_Set(vector1, 1);
+ parcBitVector_Set(vector1, 2);
+ parcBitVector_Set(vector1, 10);
+ parcBitVector_Set(vector2, 2);
+ parcBitVector_Set(vector2, 1);
+ parcBitVector_Set(vector2, 20);
+
+ PARCBitVector *result = parcBitVector_Or(vector1, vector2);
+
+ assertTrue(parcBitVector_Contains(result, vector1), "Vector contents not included in OR operation results");
+ assertTrue(parcBitVector_Contains(result, vector2), "Vector contents not included in OR operation results");
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 4, "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_Or(vector1, NULL);
+ assertTrue(parcBitVector_Equals(result, vector1), "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_Or(NULL, vector2);
+ assertTrue(parcBitVector_Equals(result, vector2), "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_Or(NULL, NULL);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ parcBitVector_Release(&vector1);
+ parcBitVector_Release(&vector2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Shift)
+{
+ PARCBitVector *vector = parcBitVector_Create();
+
+ parcBitVector_Set(vector, 0); // should drop off on left shift
+ parcBitVector_Set(vector, 11);
+ parcBitVector_Set(vector, 12);
+ parcBitVector_Set(vector, 13);
+ parcBitVector_Set(vector, 22);
+ parcBitVector_LeftShift(vector, 10);
+ parcBitVector_RightShift(vector, 10);
+ assertTrue(parcBitVector_NextBitSet(vector, 0) == 11, "Shift operations failed");
+ assertTrue(parcBitVector_NextBitSet(vector, 12) == 12, "Shift operations failed");
+ assertTrue(parcBitVector_NextBitSet(vector, 14) == 22, "Shift operations failed");
+ assertTrue(parcBitVector_NumberOfBitsSet(vector) == 4, "Shift operations failed to drop first bit on left shift");
+ parcBitVector_Release(&vector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_SetClear)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ parcBitVector_Set(parcBitVector, 10);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed");
+
+ parcBitVector_Clear(parcBitVector, 10);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Clear failed");
+
+ parcBitVector_Clear(parcBitVector, 20);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Clear failed");
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_SetVector)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ PARCBitVector *setVector = parcBitVector_Create();
+ parcBitVector_Set(parcBitVector, 1);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed");
+
+ parcBitVector_Set(setVector, 20);
+ parcBitVector_SetVector(parcBitVector, setVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "parcBitVector_SetVector failed");
+ assertTrue(parcBitVector_NextBitSet(parcBitVector, 0) == 1, "parcBitVector_Set failed to set bit 1");
+ assertTrue(parcBitVector_NextBitSet(parcBitVector, 2) == 20, "parcBitVector_SetVector failed to set bit 20");
+
+ parcBitVector_Set(setVector, 10);
+ parcBitVector_SetVector(parcBitVector, setVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 3, "parcBitVector_SetVector failed");
+ parcBitVector_Release(&parcBitVector);
+ parcBitVector_Release(&setVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Reset)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ // Reset and empty vector test
+ parcBitVector_Reset(parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Reset failed");
+
+ parcBitVector_Set(parcBitVector, 1);
+ parcBitVector_Set(parcBitVector, 42);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "parcBitVector_Set failed");
+ assertTrue(parcBitVector->bitLength == 48, "Expected a bitLength of 48");
+
+ parcBitVector_Reset(parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Reset failed");
+ assertTrue(parcBitVector->bitLength == 48, "Expected a bitLength of 48");
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_ClearVector)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ PARCBitVector *setVector = parcBitVector_Create();
+ parcBitVector_Set(parcBitVector, 1);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed to set bit");
+
+ parcBitVector_Set(setVector, 1);
+ parcBitVector_Set(setVector, 20);
+ parcBitVector_ClearVector(parcBitVector, setVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_ClearVector failed to clear vector");
+
+ parcBitVector_Set(parcBitVector, 12);
+ parcBitVector_Set(parcBitVector, 17);
+ parcBitVector_ClearVector(parcBitVector, parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_ClearVector failed to clear vector");
+
+ parcBitVector_Release(&parcBitVector);
+ parcBitVector_Release(&setVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_NextBitSet)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ int nextBit = parcBitVector_NextBitSet(parcBitVector, 0);
+ assertTrue(nextBit == -1, "parcBitVector_NextBitSet should have failed (%d)", nextBit);
+
+ parcBitVector_Set(parcBitVector, 10);
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 0);
+ assertTrue(nextBit == 10, "parcBitVector_NextBitSet failed (%d)", nextBit);
+
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 20);
+ assertTrue(nextBit == -1, "parcBitVector_NextBitSet read past end of vector (%d)", nextBit);
+
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 10);
+ assertTrue(nextBit == 10, "parcBitVector_NextBitSet failed (%d)", nextBit);
+
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 11);
+ assertTrue(nextBit == -1, "parcBitVector_NextBitSet should have failed (%d)", nextBit);
+
+ parcBitVector_Set(parcBitVector, 20);
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 11);
+ assertTrue(nextBit == 20, "parcBitVector_NextBitSet failed (%d)", nextBit);
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Get)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ parcBitVector_Set(parcBitVector, 10);
+ int bitValue = parcBitVector_Get(parcBitVector, 10);
+ assertTrue(bitValue == 1, "parcBitVector_Get returned wrong value (%d)", bitValue);
+
+ bitValue = parcBitVector_Get(parcBitVector, 11);
+ assertTrue(bitValue == 0, "parcBitVector_Get returned wrong value (%d)", bitValue);
+
+ bitValue = parcBitVector_Get(parcBitVector, 100);
+ assertTrue(bitValue == -1, "parcBitVector_NextBitSet should have failed (%d)", bitValue);
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_ToString)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ char *string = parcBitVector_ToString(parcBitVector);
+ assertTrue(strcmp(string, "[ ]") == 0, "parcBitVector_ToString returned unexpected representation (%s != [ ])", string);
+ parcMemory_Deallocate(&string);
+
+ parcBitVector_Set(parcBitVector, 10);
+ parcBitVector_Set(parcBitVector, 1);
+ string = parcBitVector_ToString(parcBitVector);
+ assertTrue(strcmp(string, "[ 1 10 ]") == 0, "parcBitVector_ToString returned unexpected representation (%s != [ 1 10 ])", string);
+ parcMemory_Deallocate(&string);
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Copy)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ parcBitVector_Set(parcBitVector, 10);
+ PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(copy) == 1, "parcBitVector_Copy failed to copy set bit");
+ assertTrue(parcBitVector_NextBitSet(copy, 0) == 10, "parcBitVector_Copy failed to copy correct bit");
+
+ parcBitVector_Release(&copy);
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Equals)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ parcBitVector_Set(parcBitVector, 10);
+ PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ assertTrue(parcBitVector_Equals(parcBitVector, copy), "Duplicate vector found unequal");
+
+ parcBitVector_Set(copy, 9);
+ assertFalse(parcBitVector_Equals(parcBitVector, copy), "Unequal vector found equal");
+
+ parcBitVector_Clear(copy, 9);
+ parcBitVector_Set(copy, 29);
+ assertFalse(parcBitVector_Equals(parcBitVector, copy), "Unequal long vector found equal");
+
+ parcBitVector_Clear(copy, 29);
+ assertTrue(parcBitVector_Equals(parcBitVector, copy), "Equal long vector found unequal");
+ assertTrue(parcBitVector_Equals(copy, parcBitVector), "Equal long vector found unequal");
+
+ parcBitVector_Release(&copy);
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Contains)
+{
+ PARCBitVector *supersetVector = parcBitVector_Create();
+
+ parcBitVector_Set(supersetVector, 10);
+ parcBitVector_Set(supersetVector, 11);
+
+ PARCBitVector *testVector = parcBitVector_Create();
+ parcBitVector_Set(testVector, 10);
+ assertTrue(parcBitVector_Contains(supersetVector, testVector), "Expect superset to contain testVector");
+
+ parcBitVector_Set(testVector, 12);
+ assertFalse(parcBitVector_Contains(supersetVector, testVector), "Expect superset to not contain testVector");
+
+ parcBitVector_Release(&supersetVector);
+ parcBitVector_Release(&testVector);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BitVector);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Buffer.c b/libparc/parc/algol/test/test_parc_Buffer.c
new file mode 100644
index 00000000..99b3bfd6
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Buffer.c
@@ -0,0 +1,1502 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Buffer.c"
+
+LONGBOW_TEST_RUNNER(parcBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(GettersSetters);
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroyErrors);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parcBuffer)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parcBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_0);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_SIZE_MAX);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap_NULL);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap_WithOffset);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_AllocateCString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate)
+{
+ PARCBuffer *actual = parcBuffer_Allocate(10);
+ assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcBuffer_Limit(actual) == 10, "Expected initial limit to be 10.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_0)
+{
+ PARCBuffer *actual = parcBuffer_Allocate(0);
+ assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcBuffer_Limit(actual) == 0, "Expected initial limit to be 10.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_SIZE_MAX)
+{
+ PARCBuffer *actual = parcBuffer_Allocate(SIZE_MAX);
+ assertNull(actual, "Expected parcBuffer_Allocate to return NULL");
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap_NULL)
+{
+ PARCBuffer *actual = parcBuffer_Wrap(NULL, 10, 0, 10);
+ assertNull(actual, "Expected parcBuffer_Wrap to return NULL");
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *actual = parcBuffer_Wrap(array, 10, 0, 10);
+ assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcBuffer_Limit(actual) == sizeof(array) / sizeof(array[0]), "Expected initial limit to be 10.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap_WithOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *actual = parcBuffer_Wrap(array, 10, 3, 10);
+ assertTrue(parcBuffer_Capacity(actual) == 10, "Expected initial capacity to be 3.");
+ assertTrue(parcBuffer_Limit(actual) == 10, "Expected initial limit to be 3.");
+ assertTrue(parcBuffer_Position(actual) == 3, "Expected initial position to be 0.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_AllocateCString)
+{
+ PARCBuffer *buffer = parcBuffer_AllocateCString("Hello World");
+ assertNotNull(buffer, "Expected parcBuffer_AllocateCString to return non-null value");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_AcquireRelease)
+{
+ PARCBuffer *expected = parcBuffer_Allocate(10);
+ PARCBuffer *actual = parcBuffer_Acquire(expected);
+
+ assertTrue(expected == actual, "Expected %p, actual %p", (void *) expected, (void *) actual);
+
+ parcBuffer_Release(&expected);
+ assertTrue(expected == NULL, "Expected parcBuffer_Release to NULL the pointer.");
+ parcBuffer_Release(&actual);
+ assertTrue(actual == NULL, "Expected parcBuffer_Release to NULL the pointer.");
+}
+
+LONGBOW_TEST_FIXTURE(CreateDestroyErrors)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroyErrors, parcBuffer_Allocate_AcquireRelease_TooMany);
+ LONGBOW_RUN_TEST_CASE(CreateDestroyErrors, parcBuffer_WrapByteArray_limit_exceeds_capacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroyErrors)
+{
+ PARCByteArray *array = parcByteArray_Allocate(10);
+ longBowTestCase_SetClipBoardData(testCase, array);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroyErrors)
+{
+ PARCByteArray *array = longBowTestCase_GetClipBoardData(testCase);
+ parcByteArray_Release(&array);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(CreateDestroyErrors, parcBuffer_Allocate_AcquireRelease_TooMany, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *expected = parcBuffer_Allocate(10);
+ PARCBuffer *actual = parcBuffer_Acquire(expected);
+ PARCBuffer *alias = actual;
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&actual);
+ parcBuffer_Release(&alias); // this must fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(CreateDestroyErrors, parcBuffer_WrapByteArray_limit_exceeds_capacity, .event = &LongBowAssertEvent)
+{
+ PARCByteArray *array = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCBuffer *buffer = parcBuffer_WrapByteArray(array, 0, parcByteArray_Capacity(array) + 1);
+
+ assertNotNull(buffer, "Expected NULL");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+// LONGBOW_RUN_TEST_CASE(Global, HELPME);
+// LONGBOW_RUN_TEST_CASE(Global, HELPME2);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Array);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ArrayOffset);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clear);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clone);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Duplicate);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clone_WithOffset);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals_ZeroLength);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals_Bug80);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Flip);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetByte);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetBytes);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetBytes_Incremental);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HasRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HashCode_ZeroRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Mark);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Growing);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Growing_AtLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Shrinking);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Shrinking_AtLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Example);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Slice);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Overlay);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Position);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBuffer_ZeroLength_operand);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutByte);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBytes);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutIndex);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutCString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Remaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Rewind);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetLimit_TruncatePosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetPosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Slice);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ToString_ZeroRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipOver);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipOver_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipTo_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipTo);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_FindUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_FindUint8_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_IsValid_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseNumeric_Decimal);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseNumeric_Hexadecimal);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseHexString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_CreateFromArray);
+}
+
+static size_t _longBowGlobal_Global_outstanding;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked);
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_CASE(Global, HELPME)
+{
+ uint8_t decodeBytes[] = { 0x00, 0x02, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *b1 = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+
+ // b1 is a buffer wrapping a byte array.
+ // This will take 2 allocations: 1 for the buffer and 1 for the wrapper around the byte array.
+
+ PARCBuffer *s2 = parcBuffer_Slice(b1);
+
+ // s2 is another buffer referencing the wrapper created in the original buffer.
+ // This will increase the allocations by 1 for the buffer making it 3.
+
+ // **** DO NOT RELEASE s2
+
+ parcBuffer_Release(&b1);
+ // This releases the b1 buffer, deallocating it. The wrapper around the original byte array still has a reference to it from s2.
+ // The number of allocations is reduced by 1, making it 2 (1 for s2, and 1 for the wrapper it references)
+
+ assertTrue(parcMemory_Outstanding() == 2, "memory imbalance");
+
+ parcBuffer_Release(&s2);
+
+ assertTrue(parcMemory_Outstanding() == 0, "memory imbalance must be 0, actual %d", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, HELPME2)
+{
+ uint8_t decodeBytes[] = { 0x00, 0x02, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *b1 = parcBuffer_Allocate(sizeof(decodeBytes));
+ // This will create a buffer, a wrapper, and an allocated array of bytes to wrap.
+ // The number of allocations is 3.
+
+ parcBuffer_PutArray(b1, sizeof(decodeBytes), decodeBytes);
+ parcBuffer_Flip(b1);
+
+ PARCBuffer *s2 = parcBuffer_Slice(b1);
+ // The number of allocations is 4.
+
+ // **** DO NOT RELEASE s2
+
+ parcBuffer_Release(&b1);
+ // The number of allocations is now 3, the slice buffer, the wrapper, and the allocated array of bytes.
+
+ // This will now correctly assert
+ assertTrue(parcMemory_Outstanding() == 3, "memory imbalance");
+
+ parcBuffer_Release(&s2);
+ assertTrue(parcMemory_Outstanding() == 0, "memory imbalance");
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Equals)
+{
+ PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *z = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+
+ // _Pragma("GCC diagnostic push")
+ // _Pragma("GCC diagnostic ignored \"-Wzero-length-array\"")
+ // _Pragma("GCC diagnostic ignored \"-Wgnu-empty-initializer\"")
+ struct hack {
+ uint8_t dummy;
+ uint8_t empty[];
+ };
+ struct hack h = { 0 };
+ PARCBuffer *u0 = parcBuffer_Wrap(h.empty, 0, 0, 0);
+ // _Pragma("GCC diagnostic pop")
+
+ PARCBuffer *u1 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10);
+ PARCBuffer *u2 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9);
+ PARCBuffer *u3 = parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9);
+ PARCBuffer *u4 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 2);
+ PARCBuffer *u5 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+ PARCBuffer *u6 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+ PARCBuffer *u7 = parcBuffer_Wrap((uint8_t [9]) { 0 }, 0, 0, 0);
+
+ parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u0, u1, u2, u3, u4, u5, u6, u7, NULL);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u0);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+ parcBuffer_Release(&u3);
+ parcBuffer_Release(&u4);
+ parcBuffer_Release(&u5);
+ parcBuffer_Release(&u6);
+ parcBuffer_Release(&u7);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Equals_ZeroLength)
+{
+ // _Pragma("GCC diagnostic push")
+ // _Pragma("GCC diagnostic ignored \"-Wzero-length-array\"")
+ // _Pragma("GCC diagnostic ignored \"-Wgnu-empty-initializer\"")
+
+ struct hack {
+ uint8_t dummy;
+ uint8_t empty[];
+ };
+ struct hack h = { 0 };
+ PARCBuffer *x = parcBuffer_Wrap(h.empty, 0, 0, 0);
+ PARCBuffer *y = parcBuffer_Wrap(h.empty, 0, 0, 0);
+ PARCBuffer *z = parcBuffer_Wrap(h.empty, 0, 0, 0);
+
+ // _Pragma("GCC diagnostic pop")
+
+ PARCBuffer *u1 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10);
+ PARCBuffer *u2 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9);
+
+ parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u1, u2, NULL);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Equals_Bug80)
+{
+ PARCBuffer *x = parcBuffer_WrapCString("a");
+ PARCBuffer *y = parcBuffer_WrapCString("a");
+ PARCBuffer *z = parcBuffer_WrapCString("a");
+ PARCBuffer *u1 = parcBuffer_WrapCString("b");
+ PARCBuffer *u2 = parcBuffer_WrapCString("");
+ PARCBuffer *u3 = parcBuffer_WrapCString("ab");
+
+ parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u1, u2, u3);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+ parcBuffer_Release(&u3);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Compare)
+{
+ PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+
+ PARCBuffer *equivalent[] = {
+ x,
+ y,
+ NULL
+ };
+ PARCBuffer *lesser[] = {
+ parcBuffer_Wrap((uint8_t [9]) { 0 }, 0, 0, 0),
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8}, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 5, 7, 8,}, 9, 0, 9),
+ NULL
+ };
+ PARCBuffer *greater[] = {
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [11]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11, 0, 11),
+ NULL
+ };
+
+ parcObjectTesting_AssertCompareTo(parcBuffer_Compare, x, equivalent, lesser, greater);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+
+ for (int i = 0; lesser[i] != NULL; i++) {
+ parcBuffer_Release(&lesser[i]);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ parcBuffer_Release(&greater[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Array)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(expected, 10, 0, 10);
+
+ PARCByteArray *array = parcBuffer_Array(buffer);
+ uint8_t *actual = parcByteArray_Array(array);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual,
+ "Expected %p, actual %p", (void *) expected, (void *) actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Growing)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(12);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_SetLimit(buffer, 11);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 20);
+
+ assertTrue(buffer->position == 5, "Expected position at %d, actual %zd", 5, buffer->position);
+ assertTrue(buffer->mark == 5, "Expected mark at %d, actual %zd", 5, buffer->mark);
+ assertTrue(buffer->limit == 11, "Expected limit at %d, actual %zd", 11, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected capacity at %d, actual %zd", 20, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Growing_AtLimit)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(12);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 20);
+
+ assertTrue(buffer->position == 5, "Expected position at %d, actual %zd", 5, buffer->position);
+ assertTrue(buffer->mark == 5, "Expected mark at %d, actual %zd", 5, buffer->mark);
+ assertTrue(buffer->limit == 20, "Expected limit at %d, actual %zd", 20, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected capacity at %d, actual %zd", 20, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Shrinking)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 3);
+ parcBuffer_SetLimit(buffer, 4);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 5);
+
+ assertTrue(buffer->position == 3, "Expected position at %d, actual %zd", 3, buffer->position);
+ assertTrue(buffer->mark == 3, "Expected mark to be 3");
+ assertTrue(buffer->limit == 4, "Expected limit at %d, actual %zd", 4, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 5, "Expected capacity at %d, actual %zd", 5, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Shrinking_AtLimit)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_SetLimit(buffer, 5);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 3);
+
+ assertTrue(buffer->position == 3, "Expected position at %d, actual %zd", 3, buffer->position);
+ assertTrue(_markIsDiscarded(buffer), "Expected mark to be discarded");
+ assertTrue(buffer->limit == 3, "Expected limit at %d, actual %zd", 3, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 3, "Expected capacity at %d, actual %zd", 3, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Example)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ parcBuffer_Resize(buffer, 4);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Slice)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ parcBuffer_SetPosition(buffer, 5);
+ PARCBuffer *slice = parcBuffer_Slice(buffer);
+
+ parcBuffer_Resize(slice, 4);
+
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&slice);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Flip)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, 10, expected);
+ parcBuffer_Flip(buffer);
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected position to be 0.");
+ assertTrue(parcBuffer_Limit(buffer) == 10, "Expected limit to be 10.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Clear)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, 10, expected);
+ parcBuffer_Clear(buffer);
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected position to be 0.");
+ assertTrue(parcBuffer_Limit(buffer) == 10, "Expected limit to be 10.");
+ assertTrue(buffer->mark >= parcBuffer_Capacity(buffer), "Expected the mark to be unset.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ArrayOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ size_t expected = 5;
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, expected, 10);
+
+ size_t actual = parcBuffer_ArrayOffset(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(0 == actual,
+ "Expected offset to be 0, actual %zd", actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Position)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 5;
+ parcBuffer_SetPosition(buffer, expected);
+
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual,
+ "Expected position to be 0, actual %zd", actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Overlay)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t expected[5] = { 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t position = 5;
+ parcBuffer_SetPosition(buffer, position);
+ uint8_t *actual = parcBuffer_Overlay(buffer, sizeof(array) - position);
+
+ assertTrue(memcmp(expected, actual, sizeof(expected)) == 0,
+ "Array contents should not be different.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Clone)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *original = parcBuffer_Wrap(array, 10, 0, 10);
+
+ PARCBuffer *clone = parcBuffer_Copy(original);
+
+ assertTrue(clone != original, "Expected the clone to be a different instance.");
+
+ assertTrue(parcBuffer_Equals(original, clone), "Expected clone to be equal to the original.");
+
+ parcBuffer_Release(&original);
+ assertNull(original, "Expected the parcBuffer_Release function to NULL the pointer.");
+
+ parcBuffer_Release(&clone);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Clone_WithOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *original = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_SetLimit(original, 9);
+ parcBuffer_SetPosition(original, 1);
+ PARCBuffer *range = parcBuffer_Slice(original);
+
+ PARCBuffer *clone = parcBuffer_Copy(range);
+
+ assertTrue(clone != original, "Expected the clone to be a different instance.");
+
+ assertTrue(parcBuffer_Equals(range, clone), "Expected clone to be equal to the original.");
+
+ parcBuffer_Release(&clone);
+ parcBuffer_Release(&range);
+ parcBuffer_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SetPosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetPosition(buffer, expected);
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SetLimit)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetLimit(buffer, expected);
+ size_t actual = parcBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SetLimit_TruncatePosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_Mark(buffer);
+
+ size_t expected = 2;
+ parcBuffer_SetLimit(buffer, expected);
+ size_t actual = parcBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Slice)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_GetUint8(buffer);
+
+ PARCBuffer *actual = parcBuffer_Slice(buffer);
+ assertTrue(parcBuffer_Position(actual) == 0,
+ "Expected position to be 0");
+ assertTrue(parcBuffer_Limit(actual) == parcBuffer_Remaining(buffer),
+ "Expected position to be %zd", parcBuffer_Remaining(buffer));
+ assertTrue(_markIsDiscarded(actual), "Expected the mark to be discarded.");
+
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Remaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetLimit(buffer, expected);
+ size_t actual = parcBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_HasRemaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ bool actual = parcBuffer_HasRemaining(buffer);
+
+ assertTrue(actual, "Expected true");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Rewind)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_SetPosition(buffer, 4);
+ size_t actual = parcBuffer_Position(buffer);
+ assertTrue(actual == 4, "Expected position to be at 4.");
+
+ parcBuffer_Rewind(buffer);
+
+ actual = parcBuffer_Position(buffer);
+ assertTrue(actual == 0, "Expected position to be at 0.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Duplicate)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_SetPosition(buffer, 4);
+
+ PARCBuffer *buffer2 = parcBuffer_Duplicate(buffer);
+
+ assertTrue(buffer != buffer2, "Expected distinct pointers to the different buffers.");
+ assertTrue(parcBuffer_Position(buffer) == parcBuffer_Position(buffer2), "Expected equal position values.");
+ assertTrue(parcBuffer_Limit(buffer) == parcBuffer_Limit(buffer2), "Expected equal limit values.");
+ assertTrue(parcBuffer_Capacity(buffer) == parcBuffer_Capacity(buffer2), "Expected equal capacity values.");
+
+ parcBuffer_Rewind(buffer);
+ assertFalse(parcBuffer_Position(buffer) == parcBuffer_Position(buffer2), "Expected unequal position values.");
+
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Mark)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetPosition(buffer, expected);
+ parcBuffer_Mark(buffer);
+ parcBuffer_SetPosition(buffer, 4);
+ parcBuffer_Reset(buffer);
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutByte)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ uint8_t expectedValue = 1;
+ parcBuffer_PutUint8(buffer, expectedValue);
+
+ size_t expectedPosition = 1;
+ size_t actualPosition = parcBuffer_Position(buffer);
+
+ parcBuffer_SetPosition(buffer, 0);
+ uint8_t actualValue = parcBuffer_GetAtIndex(buffer, 0);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expectedValue == actualValue,
+ "Expected %d, actual %d", expectedValue, actualValue);
+ assertTrue(expectedPosition == actualPosition,
+ "Expected %zu, actual %zu", expectedPosition, actualPosition);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutCString)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ char *expectedValue = "abcdefg";
+ parcBuffer_PutCString(buffer, expectedValue);
+
+ size_t expectedPosition = 8;
+ size_t actualPosition = parcBuffer_Position(buffer);
+
+ uint8_t zero = parcBuffer_GetAtIndex(buffer, 7);
+
+ assertTrue(zero == 0, "Expected zero, actual %d", zero);
+
+ assertTrue(expectedPosition == actualPosition,
+ "Expected %zu, actual %zu", expectedPosition, actualPosition);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutUint16)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ uint16_t expectedValue = 0x1234;
+ parcBuffer_PutUint16(buffer, expectedValue);
+
+ size_t expectedPosition = 2;
+ size_t actualPosition = parcBuffer_Position(buffer);
+ assertTrue(expectedPosition == actualPosition,
+ "Expected position %zd, actual %zd", expectedPosition, actualPosition);
+
+ parcBuffer_Flip(buffer);
+ uint16_t actualValue = parcBuffer_GetUint16(buffer);
+
+ actualPosition = parcBuffer_Position(buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expectedValue == actualValue,
+ "Expected %d, actual %d", expectedValue, actualValue);
+ assertTrue(expectedPosition == actualPosition,
+ "Expected %zu, actual %zu", expectedPosition, actualPosition);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutIndex)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ uint8_t expected = 1;
+ parcBuffer_PutAtIndex(buffer, 0, expected);
+ uint8_t actual = parcBuffer_GetAtIndex(buffer, 0);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual,
+ "Expected %" PRIu8 ", actual %" PRIu8 "", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutBytes)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, 10, array);
+
+ size_t expected = parcBuffer_Limit(buffer);
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected position to be at the limit.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutBuffer)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 5, array);
+
+ PARCBuffer *buffer2 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer2, 5, &array[5]);
+ parcBuffer_Flip(buffer2);
+
+ parcBuffer_PutBuffer(buffer1, buffer2);
+
+ size_t expected = parcBuffer_Limit(buffer1);
+ size_t actual = parcBuffer_Position(buffer1);
+
+ assertTrue(expected == actual, "Expected position to be at the limit. Expected %zd, actual %zd", expected, actual);
+ assertTrue(memcmp(array, parcByteArray_Array(buffer1->array), sizeof(array)) == 0,
+ "Array content differs.");
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_GetByte)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+ parcBuffer_Flip(buffer);
+
+ uint8_t actual = parcBuffer_GetUint8(buffer);
+
+ assertTrue(expected[0] == actual,
+ "Expected %d, actual %d", expected[0], actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_GetBytes)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10];
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+ parcBuffer_Flip(buffer);
+
+ parcBuffer_GetBytes(buffer, sizeof(actual), actual);
+
+ assertTrue(memcmp(expected, actual, sizeof(actual)) == 0,
+ "Expected arrays to be equal.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_GetBytes_Incremental)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10];
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+ parcBuffer_Flip(buffer);
+
+ parcBuffer_GetBytes(buffer, 1, actual);
+ assertTrue(parcBuffer_Position(buffer) == 1, "Expected position to be %d\n", 1);
+ assertTrue(actual[0] == expected[0], "Expected %d, actual %d", expected[0], actual[0]);
+ parcBuffer_GetBytes(buffer, 1, actual);
+ assertTrue(parcBuffer_Position(buffer) == 2, "Expected position to be 2, actual %zd\n", parcBuffer_Position(buffer));
+ assertTrue(actual[0] == expected[1], "Expected %d, actual %d", expected[1], actual[0]);
+ parcBuffer_GetBytes(buffer, 1, actual);
+ assertTrue(parcBuffer_Position(buffer) == 3, "Expected position to be 3, actual %zd\n", parcBuffer_Position(buffer));
+ assertTrue(actual[0] == expected[2], "Expected %d, actual %d", expected[2], actual[0]);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutBuffer_ZeroLength_operand)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 10, array);
+
+ PARCBuffer *buffer2 = parcBuffer_Allocate(0);
+ parcBuffer_PutBuffer(buffer1, buffer2);
+
+ size_t expected = parcBuffer_Limit(buffer1);
+ size_t actual = parcBuffer_Position(buffer1);
+
+ assertTrue(expected == actual, "Expected position to be at the limit.");
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_HashCode)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 10, array);
+ parcBuffer_Flip(buffer1);
+
+ PARCBuffer *buffer2 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer2, 10, array);
+ parcBuffer_Flip(buffer2);
+
+ PARCHashCode hashX = parcBuffer_HashCode(buffer1);
+ PARCHashCode hashY = parcBuffer_HashCode(buffer2);
+
+ assertTrue(hashX == hashY, "Expected %" PRIPARCHashCode ", actual %" PRIPARCHashCode, hashX, hashY);
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_HashCode_ZeroRemaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 10, array);
+
+ PARCHashCode hashX = parcBuffer_HashCode(buffer1);
+
+ assertTrue(hashX == 0, "Expected 0, actual %" PRIPARCHashCode, hashX);
+
+ parcBuffer_Release(&buffer1);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ToString)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(array) - 1);
+ parcBuffer_PutArray(buffer, sizeof(array) - 1, array);
+ parcBuffer_Flip(buffer);
+
+ char *actual = parcBuffer_ToString(buffer);
+
+ assertTrue(strcmp("hello world", actual) == 0, "Expected 'hello world', actual %s", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ToString_ZeroRemaining)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(array) - 1);
+ parcBuffer_PutArray(buffer, sizeof(array) - 1, array);
+// parcBuffer_Flip(buffer);
+
+ char *actual = parcBuffer_ToString(buffer);
+
+ assertTrue(strcmp("", actual) == 0, "Expected '', actual %s", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipOver)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ uint8_t skipOverBytes[] = { 'H', 0 };
+
+ bool actual = parcBuffer_SkipOver(buffer, 1, skipOverBytes);
+
+ assertTrue(actual, "Expected parcBuffer_SkipOver to return true.");
+
+ uint8_t peekByte = parcBuffer_PeekByte(buffer);
+
+ assertTrue(peekByte == 'e', "Expected buffer to point to 'e', actual '%c'", peekByte);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipOver_NotFound)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+
+ bool actual = parcBuffer_SkipOver(buffer, 8, (uint8_t *) "Helo Wrd");
+
+ assertFalse(actual, "Expected parcBuffer_SkipOver to return false.");
+
+ assertTrue(parcBuffer_Remaining(buffer) == 0,
+ "Expected buffer to have no remaining bytes. Actual %zd", parcBuffer_Remaining(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipTo)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ uint8_t skipToBytes[] = { 'l', 0 };
+
+ bool actual = parcBuffer_SkipTo(buffer, 1, skipToBytes);
+
+ assertTrue(actual, "Expected parcBuffer_SkipOver to return true.");
+
+ uint8_t peekByte = parcBuffer_PeekByte(buffer);
+
+ assertTrue(peekByte == 'l', "Expected buffer to point to 'l', actual '%c'", peekByte);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipTo_NotFound)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+
+ bool actual = parcBuffer_SkipTo(buffer, 1, (uint8_t *) "x");
+
+ assertFalse(actual, "Expected parcBuffer_SkipOver to return false.");
+ assertTrue(parcBuffer_Remaining(buffer) == 0,
+ "Expected buffer to have no remaining bytes. Actual %zd", parcBuffer_Remaining(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_FindUint8)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ size_t index = parcBuffer_FindUint8(buffer, 'e');
+ assertTrue(index == 1, "Expected index to be 1, actual %zu", index);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_FindUint8_NotFound)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ size_t index = parcBuffer_FindUint8(buffer, 'z');
+ assertTrue(index == SIZE_MAX, "Expected index to be SIZE_MAX, actual %zu", index);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_IsValid_True)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ bool actual = parcBuffer_IsValid(buffer);
+ assertTrue(actual, "Expected PARCBuffer to be valid");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ParseNumeric_Decimal)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("123abc");
+
+ uint64_t actual = parcBuffer_ParseNumeric(buffer);
+
+ assertTrue(actual == 123, "Expected 123, actual %" PRIu64 "", actual);
+ assertTrue(parcBuffer_Position(buffer) == 3, "Expected position to be 3, actual %zd", parcBuffer_Position(buffer));
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ParseNumeric_Hexadecimal)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("0x123xyz");
+
+ uint64_t actual = parcBuffer_ParseNumeric(buffer);
+
+ assertTrue(actual == 0x123, "Expected 0x123, actual %" PRIx64 "", actual);
+ assertTrue(parcBuffer_Position(buffer) == 5, "Expected position to be 5, actual %zd", parcBuffer_Position(buffer));
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ParseHexString)
+{
+ char *expected = "00";
+ PARCBuffer *buffer = parcBuffer_ParseHexString("3030");
+ parcBuffer_Flip(buffer);
+ char *actual = parcBuffer_ToString(buffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcMemory_Deallocate(&actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_CreateFromArray)
+{
+ char *expected = "0123456789ABCDEF";
+ PARCBuffer *buffer = parcBuffer_CreateFromArray(expected, strlen(expected));
+
+ assertTrue(parcBuffer_Position(buffer) == 16, "Expected position to be at 15, actual %zd", parcBuffer_Position(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(GettersSetters)
+{
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint8);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint16);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint32);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint64);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_ToHexString);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_ToHexString_NULLBuffer);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_Display);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_Display_NULL);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(GettersSetters)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(100);
+
+ longBowTestCase_SetClipBoardData(testCase, buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(GettersSetters)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&buffer);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint8)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t expected = 0x12;
+ parcBuffer_PutUint8(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint8_t actual = parcBuffer_GetUint8(buffer);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint16)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint16_t expected = 0x1234;
+ parcBuffer_PutUint16(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint16_t actual = parcBuffer_GetUint16(buffer);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint32)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t expected = 0x12345678;
+ parcBuffer_PutUint32(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint64)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t expected = 0x1234567812345678;
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint64_t actual = parcBuffer_GetUint64(buffer);
+
+ assertTrue(expected == actual, "Expected %" PRIu64 ", actual %" PRIu64 "", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_ToHexString)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t expected = 0x1234567812345678;
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+ char *hexString = parcBuffer_ToHexString(buffer);
+
+ assertTrue(strcmp("1234567812345678", hexString) == 0, "Expected 1234567812345678, actual %s", hexString);
+ parcMemory_Deallocate((void **) &hexString);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_ToHexString_NULLBuffer)
+{
+ char *hexString = parcBuffer_ToHexString(NULL);
+
+ assertTrue(strcmp("null", hexString) == 0, "Expected null, actual %s", hexString);
+ parcMemory_Deallocate((void **) &hexString);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_Display)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t expected = 0x1234567812345678;
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+ parcBuffer_Display(buffer, 0);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_Display_NULL)
+{
+ parcBuffer_Display(NULL, 0);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcBuffer_GetByte_Underflow);
+ LONGBOW_RUN_TEST_CASE(Errors, parcBuffer_Mark_mark_exceeds_position);
+}
+
+typedef struct parc_buffer_longbow_clipboard {
+ PARCBuffer *buffer;
+} parcBuffer_LongBowClipBoard;
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ parcBuffer_LongBowClipBoard *testData = calloc(1, sizeof(parcBuffer_LongBowClipBoard));
+ testData->buffer = parcBuffer_Allocate(10);
+
+ longBowTestCase_SetClipBoardData(testCase, testData);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&testData->buffer);
+ free(testData);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcBuffer_GetByte_Underflow, .event = &LongBowTrapOutOfBounds)
+{
+ parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = testData->buffer;
+
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ parcBuffer_PutArray(buffer, 1, expected);
+ parcBuffer_Flip(buffer);
+
+ parcBuffer_GetUint8(buffer);
+ parcBuffer_GetUint8(buffer); // this will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcBuffer_Mark_mark_exceeds_position, .event = &LongBowAssertEvent)
+{
+ parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = testData->buffer;
+
+ size_t expected = 2;
+ parcBuffer_SetPosition(buffer, expected);
+ parcBuffer_Mark(buffer);
+ parcBuffer_SetPosition(buffer, 0);
+ parcBuffer_Reset(buffer);
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _digittoint);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked);
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_CASE(Static, _digittoint)
+{
+ char *base10 = "0123456789";
+
+ for (size_t i = 0; i < strlen(base10); i++) {
+ int expected = (int) i;
+ int actual = _digittoint(base10[i]);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ }
+
+ char *base16 = "0123456789abcdef";
+
+ for (size_t i = 0; i < strlen(base16); i++) {
+ int expected = (int) i;
+ int actual = _digittoint(base16[i]);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ }
+
+ base16 = "0123456789ABCDEF";
+
+ for (size_t i = 0; i < strlen(base16); i++) {
+ int expected = (int) i;
+ int actual = _digittoint(base16[i]);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcBuffer_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked);
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_CASE(Performance, parcBuffer_Create)
+{
+ for (size_t i = 0; i < 1000000; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(1200);
+ parcBuffer_Release(&buffer);
+ }
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcBuffer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_BufferChunker.c b/libparc/parc/algol/test/test_parc_BufferChunker.c
new file mode 100755
index 00000000..8f770968
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_BufferChunker.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_BufferChunker.c"
+
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_BufferChunker)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_BufferChunker)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_BufferChunker)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_CreateFromBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_Buffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferPartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_Buffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferPartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_CreateFromBuffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+ PARCBufferChunker *copy = parcBufferChunker_Acquire(chunker);
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+ assertNotNull(copy, "Expected non-NULL copy of Chunker");
+ parcBufferChunker_Release(&copy);
+
+ parcBuffer_Release(&buffer);
+ parcBufferChunker_Release(&chunker);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_Buffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferPartial)
+{
+ // Allocate something that's not divisible by the chunk size
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferSmall)
+{
+ // Allocate something that's not divisible by the chunk size
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 16; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 16; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_Buffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", (31 - count), i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferPartial)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferSmall)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+
+ // Special 0xFF to mark the start
+ for (int i = 0; i < 16; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 16; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize)
+{
+ size_t expectedChunkSize = 32;
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, expectedChunkSize); // each chunk is 32 bytes
+ size_t actualChunkSize = parcBufferChunker_GetChunkSize(chunker);
+
+ assertTrue(actualChunkSize == expectedChunkSize, "Expected chunk size of %zu, got %zu", expectedChunkSize, actualChunkSize);
+
+ parcBuffer_Release(&buffer);
+ parcBufferChunker_Release(&chunker);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferChunker);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_BufferComposer.c b/libparc/parc/algol/test/test_parc_BufferComposer.c
new file mode 100644
index 00000000..fad9857c
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_BufferComposer.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_BufferComposer.c"
+
+#include <inttypes.h>
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+typedef struct {
+ uint32_t setupAllocations;
+ PARCBufferComposer *composer;
+} TestData;
+
+static TestData*
+commonSetup()
+{
+ uint32_t outstanding = parcSafeMemory_Outstanding();
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear of %zu bytes returned NULL.", sizeof(TestData));
+ data->setupAllocations = outstanding;
+ data->composer = parcBufferComposer_Create();
+ return data;
+}
+
+static uint32_t
+commonTearDown(TestData *data)
+{
+ uint32_t setupAllocations = data->setupAllocations;
+
+ // NOTE: The `parcBufferComposer_AssertValid_IncrementSize` invalidates this object, so we must
+ // restore it to a good state in order for all memory to be released correctly.
+ (data->composer)->incrementHeuristic = sizeof(void *);
+
+ parcBufferComposer_Release(&(data->composer));
+ parcMemory_Deallocate((void **) &data);
+ return parcSafeMemory_ReportAllocation(STDOUT_FILENO) - setupAllocations;
+}
+
+LONGBOW_TEST_RUNNER(parc_BufferComposer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_BufferComposer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_BufferComposer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Allocate_SizeMax);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid_IncrementSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutStrings);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Format);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutChar);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_GetBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_CreateBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_ProduceBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutString_Extend);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = commonSetup();
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t outstandingAllocations = commonTearDown(data);
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Acquire)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBufferComposer *handle = parcBufferComposer_Acquire(composer);
+
+ assertNotNull(handle, "Acquired PARCBufferComposer handle should be non-NULL.");
+ assertTrue(parcBufferComposer_Equals(composer, handle), "PARCBufferComposer instances should be equal");
+
+ parcBufferComposer_Release(&handle);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Allocate)
+{
+ size_t size = 10;
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(size);
+ PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+ assertTrue(parcBuffer_Limit(buffer) == size,
+ "PARCBufferComposer instance's internal PARCBuffer limit must be %zu: %zu", size, parcBuffer_Limit(buffer));
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Allocate_SizeMax)
+{
+ size_t size = SIZE_MAX;
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(size);
+
+ assertNull(composer, "PARCBufferComposer instance should be NULL.");
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_AssertValid)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+ parcBufferComposer_AssertValid(composer);
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcBufferComposer_AssertValid_NULL, .event = &LongBowTrapIllegalValue)
+{
+ parcBufferComposer_AssertValid(NULL);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcBufferComposer_AssertValid_IncrementSize, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ (data->composer)->incrementHeuristic = 0; // must be >= sizeof(void *)
+ parcBufferComposer_AssertValid(data->composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Create)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Equals)
+{
+ PARCBufferComposer *x = parcBufferComposer_Create();
+ PARCBufferComposer *y = parcBufferComposer_Create();
+ PARCBufferComposer *z = parcBufferComposer_Create();
+ PARCBufferComposer *u = parcBufferComposer_Allocate(10);
+
+ parcObjectTesting_AssertEqualsFunction(parcBufferComposer_Equals, x, y, z, u);
+
+ u->incrementHeuristic = 0;
+ assertFalse(parcBufferComposer_Equals(x, u), "PARCBufferComposer instances should be unequal due to size increments.");
+ assertFalse(parcBufferComposer_Equals(x, NULL), "Equals should return false since the second parameter is NULL.");
+ u->incrementHeuristic = sizeof(void *);
+
+ parcBufferComposer_Release(&x);
+ parcBufferComposer_Release(&y);
+ parcBufferComposer_Release(&z);
+ parcBufferComposer_Release(&u);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_ToString)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer, "hello %s", "world");
+
+ char *string = parcBufferComposer_ToString(composer);
+
+ assertNotNull(string, "Expected non-NULL result from parcBufferComposer_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_GetBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+ assertNotNull(buffer, "PARCBufferComposer instance's internal PARCBuffer should not be NULL");
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutArray)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint8_t string[6] = { 'h', 'e', 'l', 'l', 'o', '\0' };
+ parcBufferComposer_PutArray(composer, string, 6);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[5] = "hello";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 5) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *insertee = parcBuffer_WrapCString("hello world");
+ parcBufferComposer_PutBuffer(composer, insertee);
+ parcBuffer_Release(&insertee);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint16)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint16_t val = 0x0101;
+ parcBufferComposer_PutUint16(composer, val);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint16(buffer) == val, "Expected inserted uint16_t to be equal to %x, got %x", val, parcBuffer_GetUint16(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint32)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint32_t val = 0x0101FFFF;
+ parcBufferComposer_PutUint32(composer, val);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint32(buffer) == val, "Expected inserted uint32_t to be equal to %x, got %x", val, parcBuffer_GetUint32(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint64)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint64_t val = 0x0101FFFFABCD0123;
+ parcBufferComposer_PutUint64(composer, val);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint64(buffer) == val,
+ "Expected inserted uint64_t to be equal to %" PRIu64 ", got %" PRIu64 "", val, parcBuffer_GetUint64(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint8)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint8_t byte = 0x01;
+ parcBufferComposer_PutUint8(composer, byte);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint8(buffer) == byte, "Expected inserted byte to be equal to %x, got %x", byte, parcBuffer_GetUint8(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutString)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char string[14] = "Hello, World!";
+ parcBufferComposer_PutString(composer, string);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(actual, string, strlen(string)) == 0,
+ "Expected inserted string to be equal to %s, got %s", string, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutStrings)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char string[14] = "Hello, World!";
+ parcBufferComposer_PutStrings(composer, "Hello", ", ", "World!", NULL);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(actual, string, strlen(string)) == 0, "Expected inserted string to be equal to %s, got %s", string, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Format)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer, "hello %s", "world");
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutChar)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char byte = 'a';
+ parcBufferComposer_PutChar(composer, byte);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint8(buffer) == byte, "Expected inserted char to be equal to %c, got %c", byte, parcBuffer_GetUint8(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_CreateBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "hello world");
+
+ PARCBuffer *buffer = parcBufferComposer_CreateBuffer(composer);
+ parcBuffer_Flip(buffer); // flip the buffer since it was returned in write mode
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_ProduceBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "hello world");
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutString_Extend)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(4);
+ parcBufferComposer_PutString(composer, "hello world");
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferComposer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_ByteArray.c b/libparc/parc/algol/test/test_parc_ByteArray.c
new file mode 100755
index 00000000..971d79dd
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_ByteArray.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file test_parc_ByteArray.c
+ *
+ */
+#include "../parc_ByteArray.c"
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(PARCByteArray)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(PARCByteArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCByteArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Acquire_destroyoriginal);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Allocate_ZeroLength);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap_ZeroLength);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Array);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_AddressOfIndex);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Capacity);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Copy_Allocated);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Copy_Wrapped);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_PutBytes);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_CopyOut);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_CopyInByteArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Get);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Put);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Allocate)
+{
+ PARCByteArray *actual = parcByteArray_Allocate(10);
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Allocate_ZeroLength)
+{
+ PARCByteArray *actual = parcByteArray_Allocate(0);
+ assertNotNull(actual, "parcByteArray_Allocate(0) must not return NULL.");
+ assertTrue(parcByteArray_Capacity(actual) == 0, "Expected capacity to be 0");
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Wrap)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Wrap_NULL)
+{
+ PARCByteArray *actual = parcByteArray_Wrap(10, NULL);
+
+ assertNull(actual, "Expected NULL return value from parcByteArray_Wrap()");
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Wrap_ZeroLength)
+{
+ PARCByteArray *actual = parcByteArray_Wrap(0, (uint8_t[1]) { 0 });
+
+ assertNotNull(actual, "Expected non-NULL return value from parcByteArray_Wrap()");
+ assertTrue(parcByteArray_Capacity(actual) == 0, "Expected capacity to be zero.");
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Array)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+ assertTrue(buffer == parcByteArray_Array(actual), "Expected the array to be the wrapped array.");
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_AddressOfIndex)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+ uint8_t *address = parcByteArray_AddressOfIndex(actual, 3);
+
+ assertTrue(buffer[3] == *address,
+ "Expected %d, actual %d", buffer[3], *address);
+
+ parcByteArray_Release(&actual);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Release)
+{
+ PARCByteArray *actual = parcByteArray_Allocate(10);
+
+ parcByteArray_Release(&actual);
+ assertNull(actual, "Expected the pointer to be NULL after parcByteArray_Release");
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Copy_Allocated)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Allocate(sizeof(buffer));
+ parcByteArray_PutBytes(original, 0, sizeof(buffer), buffer);
+
+ PARCByteArray *clone = parcByteArray_Copy(original);
+
+ assertTrue(original != clone, "Expected clone to be a different instance that original.");
+
+ assertTrue(parcByteArray_Equals(original, clone), "Expected the clone to be equal to the original.");
+
+ parcByteArray_Release(&original);
+ parcByteArray_Release(&clone);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Copy_Wrapped)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Wrap(sizeof(buffer), buffer);
+
+ PARCByteArray *clone = parcByteArray_Copy(original);
+
+ assertTrue(original != clone, "Expected clone to be a different instance that original.");
+
+ assertTrue(parcByteArray_Equals(original, clone), "Expected the clone to be equal to the original.");
+
+ parcByteArray_Release(&original);
+ parcByteArray_Release(&clone);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Compare)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *x = parcByteArray_Wrap(sizeof(buffer), buffer);
+
+ PARCByteArray **equivalents = (PARCByteArray *[]) {
+ parcByteArray_Wrap(sizeof(buffer), buffer),
+ NULL
+ };
+ PARCByteArray **lessers = (PARCByteArray *[]) {
+ parcByteArray_Wrap(sizeof(buffer) - 1, buffer),
+ parcByteArray_Wrap(sizeof(buffer) - 1, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }),
+ NULL
+ };
+ PARCByteArray **greaters = (PARCByteArray *[]) {
+ parcByteArray_Wrap(11, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }),
+ parcByteArray_Wrap(10, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }),
+ NULL
+ };
+ /*
+ * (a - b)
+ */
+ parcObjectTesting_AssertCompareTo(parcByteArray_Compare, x, equivalents, lessers, greaters);
+
+ parcByteArray_Release(&x);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ parcByteArray_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ parcByteArray_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ parcByteArray_Release(&greaters[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Equals)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *x = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *y = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *z = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *u1 = parcByteArray_Wrap(5, buffer);
+ PARCByteArray *u2 = parcByteArray_Allocate(5);
+
+ parcObjectTesting_AssertEqualsFunction(parcByteArray_Equals, x, y, z, u1, u2, NULL);
+
+ parcByteArray_Release(&x);
+ parcByteArray_Release(&y);
+ parcByteArray_Release(&z);
+ parcByteArray_Release(&u1);
+ parcByteArray_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Capacity)
+{
+ size_t expected = 10;
+
+ PARCByteArray *actual = parcByteArray_Allocate(expected);
+ assertTrue(expected == parcByteArray_Capacity(actual), "Expected %zd, actual %zd", expected, parcByteArray_Capacity(actual));
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_CopyOut)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10];
+
+ PARCByteArray *original = parcByteArray_Wrap(10, expected);
+ parcByteArray_GetBytes(original, 0, sizeof(actual), actual);
+
+ assertTrue(memcmp(expected, actual, sizeof(actual)) == 0,
+ "Expected parcByteArray_CopyOut to copy the orginal data");
+
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_PutBytes)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, expected);
+ parcByteArray_PutBytes(original, 0, 10, actual);
+
+ assertTrue(memcmp(expected, actual, 10) == 0,
+ "Expected parcByteArray_CopyOut to copy the orginal data");
+
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_CopyInByteArray)
+{
+ uint8_t array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t array2[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ uint8_t expected[10] = { 0, 1, 2, 0, 0, 0, 6, 7, 8, 9 };
+
+ PARCByteArray *a1 = parcByteArray_Wrap(10, array1);
+ PARCByteArray *a2 = parcByteArray_Wrap(10, array2);
+ parcByteArray_ArrayCopy(a1, 3, a2, 0, 3);
+
+ assertTrue(memcmp(expected, parcByteArray_Array(a1), 10) == 0,
+ "Expected parcByteArray_CopyOut to copy the orginal data");
+
+ parcByteArray_Release(&a1);
+ parcByteArray_Release(&a2);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Get)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, buffer);
+
+ for (uint8_t index = 0; index < 10; index++) {
+ uint8_t actual = parcByteArray_GetByte(original, index);
+ assertTrue(index == actual, "Expected %d, actual %d", index, actual);
+ }
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Put)
+{
+ uint8_t buffer[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, buffer);
+
+ for (uint8_t index = 0; index < 10; index++) {
+ parcByteArray_PutByte(original, index, index);
+ }
+
+ for (uint8_t index = 0; index < 10; index++) {
+ uint8_t actual = parcByteArray_GetByte(original, index);
+ assertTrue(index == actual, "Expected %d, actual %d", index, actual);
+ }
+
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Acquire)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *reference = parcByteArray_Acquire(actual);
+
+ assertTrue(reference == actual, "Expected the new reference to be equal to the original.");
+
+ PARCByteArray *new1 = parcByteArray_Acquire(actual);
+ assertTrue(new1 == actual, "Expected new to be the same as actual");
+
+ PARCByteArray *new2 = parcByteArray_Acquire(actual);
+ assertTrue(new2 == actual, "Expected new to be the same as actual");
+
+ parcByteArray_Release(&new1);
+ assertNull(new1, "Expected destroy to null the pointer");
+ assertNotNull(actual, "Expected destroy to NOT null the original pointer");
+
+ parcByteArray_Release(&new2);
+ assertNull(new1, "Expected destroy to null the pointer");
+ assertNotNull(actual, "Expected destroy to NOT null the original pointer");
+
+ parcByteArray_Release(&reference);
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Acquire_destroyoriginal)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, buffer);
+
+ PARCByteArray *ref1 = parcByteArray_Acquire(original);
+ assertTrue(ref1 == original, "Expected new to be the same as original");
+
+ parcByteArray_Release(&original);
+ assertNull(original, "Expected destroy to null the pointer");
+ assertNotNull(ref1, "Expected destroy to NOT null the new reference");
+
+ parcByteArray_Release(&ref1);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_HashCode)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *x = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *y = parcByteArray_Wrap(10, buffer);
+
+ PARCHashCode hashX = parcByteArray_HashCode(x);
+ PARCHashCode hashY = parcByteArray_HashCode(y);
+
+ assertTrue(hashX == hashY,
+ "Expected %" PRIPARCHashCode ", actual %" PRIPARCHashCode, hashX, hashY);
+
+ parcByteArray_Release(&x);
+ parcByteArray_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Display)
+{
+ uint8_t buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
+
+ PARCByteArray *x = parcByteArray_Wrap(sizeof(buffer), buffer);
+
+ parcByteArray_Display(x, 0);
+
+ parcByteArray_Release(&x);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_Put_overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_Get_overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_CopyIn_overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_CopyOut_overrun);
+}
+
+typedef struct parc_byte_array_longbow_clipboard {
+ PARCByteArray *byteArray;
+} parcByteArray_LongBowClipBoard;
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ parcByteArray_LongBowClipBoard *clipboardData = calloc(1, sizeof(parcByteArray_LongBowClipBoard));
+ clipboardData->byteArray = parcByteArray_Allocate(10);
+
+ longBowTestCase_SetClipBoardData(testCase, clipboardData);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ parcByteArray_LongBowClipBoard *clipboardData = longBowTestCase_GetClipBoardData(testCase);
+ parcByteArray_Release(&clipboardData->byteArray);
+ free(clipboardData);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_Put_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+
+ for (uint8_t index = 0; index < 10 + 1; index++) {
+ parcByteArray_PutByte(original, index, index); // This will fail.
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_CopyIn_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ uint8_t actual[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+ parcByteArray_GetBytes(original, 1, 10, actual); // This will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_CopyOut_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ uint8_t actual[10];
+
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+ parcByteArray_GetBytes(original, 1, 10, actual); // This will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_Get_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+ parcByteArray_PutBytes(original, 0, 10, buffer);
+
+ for (uint8_t index = 0; index < 10 + 1; index++) {
+ uint8_t actual = parcByteArray_GetByte(original, index); // this will fail.
+ assertTrue(index == actual, "Expected %d, actual %d", index, actual);
+ }
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCByteArray);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Chunker.c b/libparc/parc/algol/test/test_parc_Chunker.c
new file mode 100755
index 00000000..945e6bab
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Chunker.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Chunker.c"
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+typedef struct {
+ int val;
+ int dir;
+ bool atEnd;
+} _DummyChunkerState;
+
+typedef struct {
+ int start;
+ int end;
+ bool released;
+ size_t chunkSize;
+} _DummyChunker;
+
+static void *
+_InitForward(_DummyChunker *chunker)
+{
+ _DummyChunkerState *state = parcMemory_Allocate(sizeof(_DummyChunkerState));
+
+ state->val = 0;
+ state->dir = 1;
+ state->atEnd = false;
+
+ return state;
+}
+
+static bool
+_hasNext(_DummyChunker *chunker, void *voidstate)
+{
+ _DummyChunkerState *state = (_DummyChunkerState *) voidstate;
+ return !state->atEnd;
+}
+
+static void *
+_next(_DummyChunker *chunker, void *voidstate)
+{
+ _DummyChunkerState *state = (_DummyChunkerState *) voidstate;
+ state->val++;
+
+ if (state->val == chunker->end) {
+ state->atEnd = true;
+ }
+
+ return state;
+}
+
+static void *
+_get(_DummyChunker *chunker, void *voidstate)
+{
+ _DummyChunkerState *state = (_DummyChunkerState *) voidstate;
+ return &(state->val);
+}
+
+static void
+_finish(_DummyChunker *chunker, void *state)
+{
+ _DummyChunkerState *thestate = (_DummyChunkerState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static PARCIterator *
+_mock_ForwardIterator(const void *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_hasNext,
+ (void *(*)(PARCObject *, void *))_next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_get,
+ (void (*)(void *, void *))_finish,
+ NULL);
+
+ return iterator;
+}
+
+static PARCIterator *
+_mock_ReverseIterator(const void *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_hasNext,
+ (void *(*)(PARCObject *, void *))_next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_get,
+ (void (*)(void *, void *))_finish,
+ NULL);
+
+ return iterator;
+}
+
+static size_t
+_mock_GetChunkSize(const void *chunker)
+{
+ _DummyChunker *dummy = (_DummyChunker *) chunker;
+ return dummy->chunkSize;
+}
+
+static void
+_dummyDestroy(_DummyChunker **chunkerP)
+{
+ // pass...
+}
+
+PARCChunkerInterface *_MockChunker = &(PARCChunkerInterface) {
+ .ForwardIterator = (void *(*)(const void *))_mock_ForwardIterator,
+ .ReverseIterator = (void *(*)(const void *))_mock_ReverseIterator,
+ .GetChunkSize = (size_t (*)(const void *))_mock_GetChunkSize
+};
+
+parcObject_ExtendPARCObject(_DummyChunker, _dummyDestroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(_dummy, _DummyChunker);
+parcObject_ImplementRelease(_dummy, _DummyChunker);
+
+static _DummyChunker *
+_dummy_Create(int val)
+{
+ _DummyChunker *chunker = (_DummyChunker *) parcObject_CreateAndClearInstance(_DummyChunker);
+ chunker->start = 0;
+ chunker->end = val;
+ chunker->released = false;
+ chunker->chunkSize = val;
+ return chunker;
+}
+
+LONGBOW_TEST_RUNNER(parc_Chunker)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Chunker)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Chunker)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_Create)
+{
+ _DummyChunker *dummy = _dummy_Create(10);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+
+ assertNotNull(chunker, "Expected non-NULL PARCChunker to be created from the dummy MockChunker");
+ PARCChunker *copy = parcChunker_Acquire(chunker);
+ assertNotNull(copy, "Expected non-NULL copy of the PARCChunker");
+
+ parcChunker_Release(&chunker);
+ parcChunker_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator)
+{
+ int n = 10;
+
+ _DummyChunker *dummy = _dummy_Create(n);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+ PARCIterator *itr = parcChunker_ForwardIterator(chunker);
+
+ int targetSum = (n * (n + 1)) / 2;
+ int sum = 0;
+ while (parcIterator_HasNext(itr)) {
+ int *val = parcIterator_Next(itr);
+ sum += *val;
+ }
+ assertTrue(targetSum == sum, "Expected the iterator to walk the chunker as needed\n");
+
+ parcIterator_Release(&itr);
+ parcChunker_Release(&chunker);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator)
+{
+ int n = 10;
+
+ _DummyChunker *dummy = _dummy_Create(n);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+ PARCIterator *itr = parcChunker_ReverseIterator(chunker);
+
+ int targetSum = (n * (n + 1)) / 2;
+ int sum = 0;
+ while (parcIterator_HasNext(itr)) {
+ int *val = parcIterator_Next(itr);
+ sum += *val;
+ }
+ assertTrue(targetSum == sum, "Expected the iterator to walk the chunker as needed\n");
+
+ parcIterator_Release(&itr);
+ parcChunker_Release(&chunker);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize)
+{
+ int n = 10;
+
+ _DummyChunker *dummy = _dummy_Create(n);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+
+ size_t chunkSize = parcChunker_GetChunkSize(chunker);
+ assertTrue(chunkSize == n, "Expected the chunk size to be %d, got %zu\n", n, chunkSize);
+
+ parcChunker_Release(&chunker);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Chunker);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Clock.c b/libparc/parc/algol/test/test_parc_Clock.c
new file mode 100644
index 00000000..0adf813e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Clock.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Clock.c"
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Clock)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Clock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Clock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==========================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_GetTime);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_GetTimeval);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Montonic);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_GetTime);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_GetTimeval);
+
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_Create);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTime);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTime_Twice);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTimeval);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ assertNotNull(clock, "Got null wall clock");
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock_Acquire)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ PARCClock *copy = parcClock_Acquire(clock);
+ assertNotNull(copy, "Got null wall clock");
+ parcClock_Release(&copy);
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock_GetTime)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ uint64_t t = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t > 0, "got 0 time");
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock_GetTimeval)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ struct timeval tv = { 0, 0 };
+ parcClock_GetTimeval(clock, &tv);
+ parcClock_Release(&clock);
+ assertTrue(tv.tv_sec > 0, "Got 0 seconds");
+}
+
+// -----
+
+LONGBOW_TEST_CASE(Global, parcClock_Montonic)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ assertNotNull(clock, "Got null wall clock");
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Monotonic_Acquire)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ PARCClock *copy = parcClock_Acquire(clock);
+ assertNotNull(copy, "Got null wall clock");
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Monotonic_GetTime)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ uint64_t t = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t > 0, "got 0 time");
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Monotonic_GetTimeval)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ struct timeval tv = { 0, 0 };
+ parcClock_GetTimeval(clock, &tv);
+ parcClock_Release(&clock);
+ assertTrue(tv.tv_sec > 0, "Got 0 seconds");
+}
+
+// -----
+
+LONGBOW_TEST_CASE(Global, counterClock_Create)
+{
+ PARCClock *clock = parcClock_Counter();
+ assertNotNull(clock, "Got null wall clock");
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_Acquire)
+{
+ PARCClock *clock = parcClock_Counter();
+ PARCClock *copy = parcClock_Acquire(clock);
+ assertNotNull(copy, "Got null wall clock");
+ parcClock_Release(&copy);
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_GetTime)
+{
+ PARCClock *clock = parcClock_Counter();
+ uint64_t t = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t == 1, "On first call should have gotten 1");
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_GetTime_Twice)
+{
+ PARCClock *clock = parcClock_Counter();
+ parcClock_GetTime(clock);
+ uint64_t t2 = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t2 == 2, "On second call should have gotten 2");
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_GetTimeval)
+{
+ PARCClock *clock = parcClock_Counter();
+ struct timeval tv = { 0, 0 };
+ parcClock_GetTimeval(clock, &tv);
+ parcClock_Release(&clock);
+ assertTrue(tv.tv_usec == 1, "On first call should have gotten 1 usec");
+}
+
+
+// ==========================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Clock);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
diff --git a/libparc/parc/algol/test/test_parc_Deque.c b/libparc/parc/algol/test/test_parc_Deque.c
new file mode 100755
index 00000000..02884b4a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Deque.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_Deque.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Deque)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+// LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Deque)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Deque)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_CreateRelease_WithEquals);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("bailing\n");
+ exit(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcDeque_CreateRelease)
+{
+ PARCDeque *deque = parcDeque_Create();
+ assertNotNull(deque, "Expected non-null result from parcDeque_Create()");
+
+ parcDeque_Release(&deque);
+ assertNull(deque, "Expected parcDeque_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcDeque_CreateRelease_WithEquals)
+{
+ PARCDeque *deque = parcDeque_CreateCustom(NULL, NULL);
+ assertNotNull(deque, "Expected non-null result from parcDeque_Create()");
+
+ parcDeque_Release(&deque);
+ assertNull(deque, "Expected parcDeque_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcDeque_AcquireRelease)
+{
+ PARCDeque *original = parcDeque_Create();
+ assertNotNull(original, "Expected non-null result from parcDeque_Create()");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcDeque_Acquire, original);
+
+ PARCDeque *reference = parcDeque_Acquire(original);
+ assertTrue(original == reference, "Expected the reference to be equal to the original.");
+
+ parcDeque_Release(&original);
+ assertNull(original, "Expected parcDeque_Release to null the pointer");
+
+ parcDeque_Append(reference, (void *) 1);
+ size_t expected = 1;
+ size_t actual = parcDeque_Size(reference);
+ assertTrue(expected == actual,
+ "Expected size %zd, actual %zd", expected, actual);
+ parcDeque_Release(&reference);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Append_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Append_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_PeekFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_PeekLast);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_Three);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_IsEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_GetAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveFirst_SingleElement);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveLast);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Display_NULL);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Iterator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Append_One)
+{
+ PARCDeque *deque = parcDeque_Create();
+ PARCDeque *actual = parcDeque_Append(deque, "element 1");
+
+ assertTrue(deque == actual, "Expected parcDeque_Append to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 1, "Expected size of 1, actual %zd", parcDeque_Size(deque));
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Append_Two)
+{
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, "element 1");
+ PARCDeque *actual = parcDeque_Append(deque, "element 2");
+
+ assertTrue(deque == actual, "Expected parcDeque_Append to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 2, "Expected size of 2, actual %zd", parcDeque_Size(deque));
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_CreateDestroy)
+{
+ PARCDeque *deque = parcDeque_Create();
+ assertNotNull(deque, "Expected non-null result from parcDeque_Create()");
+
+ parcDeque_Release(&deque);
+ assertNull(deque, "Expected parcDeque_Destroy to null the pointer");
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_PeekFirst)
+{
+ char *expected = "element 2";
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, expected);
+ parcDeque_Append(deque, "element 2");
+ parcDeque_Append(deque, "element 3");
+
+ char *actual = parcDeque_PeekFirst(deque);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_PeekLast)
+{
+ char *expected = "element 2";
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, "element 1");
+ parcDeque_Append(deque, "element 2");
+ parcDeque_Append(deque, expected);
+
+ char *actual = parcDeque_PeekLast(deque);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Prepend_One)
+{
+ PARCDeque *deque = parcDeque_Create();
+ PARCDeque *actual = parcDeque_Prepend(deque, "element 1");
+
+ assertTrue(deque == actual, "Expected parcDeque_Append to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 1, "Expected size of 1, actual %zd", parcDeque_Size(deque));
+ assertTrue(deque->head != NULL, "Expected head to be not null.");
+ assertTrue(deque->head == deque->tail, "Expected head to be equal to the tail.");
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Prepend_Two)
+{
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, "element 2");
+ PARCDeque *actual = parcDeque_Prepend(deque, "element 1");
+
+ assertTrue(deque == actual, "Expected parcDeque_Prepend to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 2, "Expected size of 2, actual %zd", parcDeque_Size(deque));
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Prepend_Three)
+{
+ char *expectedFirst = "expected first";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ PARCDeque *actual = parcDeque_Prepend(deque, expectedFirst);
+
+ assertTrue(deque == actual, "Expected parcDeque_Prepend to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 3, "Expected size of 3, actual %zd", parcDeque_Size(deque));
+
+ char *peek = parcDeque_PeekFirst(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0, "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ peek = parcDeque_PeekLast(deque);
+ assertTrue(strcmp(expectedLast, peek) == 0, "Expected '%s' actual '%s'", expectedLast, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveFirst)
+{
+ char *expectedFirst = "expected 1st";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveFirst(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0, "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveFirst_SingleElement)
+{
+ char *expectedFirst = "expected 1st";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveFirst(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0,
+ "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveLast)
+{
+ char *expectedFirst = "expected 1st";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveLast(deque);
+ assertTrue(strcmp(expectedLast, peek) == 0,
+ "Expected '%s' actual '%s'", expectedLast, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveLast_SingleElement)
+{
+ char *expectedFirst = "expected 1st";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveLast(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0,
+ "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Size)
+{
+ char *expectedFirst = "expected 1st";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ parcDeque_Prepend(deque, expectedFirst);
+
+ assertTrue(parcDeque_Size(deque) == 3,
+ "Expected 3, actual %zd", parcDeque_Size(deque));
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_IsEmpty)
+{
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+
+ assertTrue(parcDeque_IsEmpty(deque), "Expected true.");
+ parcDeque_Prepend(deque, expectedLast);
+ assertFalse(parcDeque_IsEmpty(deque), "Expected false.");
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_GetAtIndex)
+{
+ char *expected0 = "expected 1";
+ char *expected1 = "expected 2";
+ char *expected2 = "expected 3";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, expected0);
+ parcDeque_Append(deque, expected1);
+ parcDeque_Append(deque, expected2);
+
+ char *actual;
+ actual = parcDeque_GetAtIndex(deque, 0);
+ assertTrue(strcmp(actual, expected0) == 0, "Expected '%s', actual '%s", expected0, actual);
+ actual = parcDeque_GetAtIndex(deque, 1);
+ assertTrue(strcmp(actual, expected1) == 0, "Expected '%s', actual '%s", expected1, actual);
+ actual = parcDeque_GetAtIndex(deque, 2);
+ assertTrue(strcmp(actual, expected2) == 0, "Expected '%s', actual '%s", expected2, actual);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Equals)
+{
+ PARCDeque *x = parcDeque_Create();
+ parcDeque_Append(x, (void *) 0);
+ parcDeque_Append(x, (void *) 1);
+ parcDeque_Append(x, (void *) 2);
+ parcDeque_Append(x, (void *) 3);
+ parcDeque_Append(x, (void *) 4);
+ parcDeque_Append(x, (void *) 5);
+ PARCDeque *y = parcDeque_Create();
+ parcDeque_Append(y, (void *) 0);
+ parcDeque_Append(y, (void *) 1);
+ parcDeque_Append(y, (void *) 2);
+ parcDeque_Append(y, (void *) 3);
+ parcDeque_Append(y, (void *) 4);
+ parcDeque_Append(y, (void *) 5);
+ PARCDeque *z = parcDeque_Create();
+ parcDeque_Append(z, (void *) 0);
+ parcDeque_Append(z, (void *) 1);
+ parcDeque_Append(z, (void *) 2);
+ parcDeque_Append(z, (void *) 3);
+ parcDeque_Append(z, (void *) 4);
+ parcDeque_Append(z, (void *) 5);
+ PARCDeque *u1 = parcDeque_Create();
+ parcDeque_Append(u1, (void *) 0);
+ parcDeque_Append(u1, (void *) 1);
+ parcDeque_Append(u1, (void *) 2);
+ parcDeque_Append(u1, (void *) 3);
+ parcDeque_Append(u1, (void *) 4);
+ PARCDeque *u2 = parcDeque_Create();
+ parcDeque_Append(u2, (void *) 0);
+ parcDeque_Append(u2, (void *) 1);
+ parcDeque_Append(u2, (void *) 2);
+ parcDeque_Append(u2, (void *) 3);
+ parcDeque_Append(u2, (void *) 4);
+ parcDeque_Append(u2, (void *) 4);
+
+ parcObjectTesting_AssertEqualsFunction(parcDeque_Equals, x, y, z, u1, u2, NULL);
+
+ parcDeque_Release(&x);
+ parcDeque_Release(&y);
+ parcDeque_Release(&z);
+ parcDeque_Release(&u1);
+ parcDeque_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Copy)
+{
+ PARCDeque *x = parcDeque_Create();
+ parcDeque_Append(x, (void *) 0);
+ parcDeque_Append(x, (void *) 1);
+ parcDeque_Append(x, (void *) 2);
+ parcDeque_Append(x, (void *) 3);
+ parcDeque_Append(x, (void *) 4);
+ parcDeque_Append(x, (void *) 5);
+
+ PARCDeque *y = parcDeque_Copy(x);
+
+ assertTrue(parcDeque_Equals(x, y), "Expected the copy to be equal to the original.");
+
+ parcDeque_Release(&y);
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Display)
+{
+ PARCDeque *x = parcDeque_Create();
+ parcDeque_Append(x, (void *) 0);
+ parcDeque_Append(x, (void *) 1);
+ parcDeque_Append(x, (void *) 2);
+ parcDeque_Append(x, (void *) 3);
+ parcDeque_Append(x, (void *) 4);
+ parcDeque_Append(x, (void *) 5);
+
+ parcDeque_Display(x, 0);
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Display_NULL)
+{
+ parcDeque_Display(NULL, 0);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Iterator)
+{
+ PARCDeque *x = parcDeque_Create();
+ for (size_t i = 0; i < 100; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ PARCIterator *iterator = parcDeque_Iterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = (size_t) parcIterator_Next(iterator);
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _parcDequeNode_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _parcDequeNode_Create)
+{
+ void *element = "element";
+ struct parc_deque_node *previous = NULL;
+ struct parc_deque_node *next = NULL;
+
+ struct parc_deque_node *actual = _parcDequeNode_Create(element, previous, next);
+ _parcDequeNode_Destroy(NULL, &actual);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcDeque_GetAtIndex_OutOfBounds);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ PARCDeque *deque = parcDeque_Create();
+ longBowTestCase_SetClipBoardData(testCase, deque);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ PARCDeque *deque = longBowTestCase_GetClipBoardData(testCase);
+ parcDeque_Release(&deque);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcDeque_GetAtIndex_OutOfBounds, .event = &LongBowTrapOutOfBounds)
+{
+ char *expected0 = "expected 1";
+ char *expected1 = "expected 2";
+ char *expected2 = "expected 3";
+
+ PARCDeque *deque = longBowTestCase_GetClipBoardData(testCase);
+ parcDeque_Append(deque, expected0);
+ parcDeque_Append(deque, expected1);
+ parcDeque_Append(deque, expected2);
+
+ parcDeque_GetAtIndex(deque, 3);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcQueue_Append);
+ LONGBOW_RUN_TEST_CASE(Performance, parcQueue_N2);
+ LONGBOW_RUN_TEST_CASE(Performance, parcQueue_Iterator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcQueue_Append)
+{
+ PARCDeque *x = parcDeque_Create();
+
+ for (size_t i = 0; i < 100000; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcQueue_N2)
+{
+ PARCDeque *x = parcDeque_Create();
+ for (size_t i = 0; i < 100000; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ for (size_t expected = 0; expected < parcDeque_Size(x); expected++) {
+ size_t actual = (size_t) parcDeque_GetAtIndex(x, expected);
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ }
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcQueue_Iterator)
+{
+ PARCDeque *x = parcDeque_Create();
+ for (size_t i = 0; i < 100000; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ PARCIterator *iterator = parcDeque_Iterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = (size_t) parcIterator_Next(iterator);
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcDeque_Release(&x);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Deque);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Dictionary.c b/libparc/parc/algol/test/test_parc_Dictionary.c
new file mode 100644
index 00000000..095f3c98
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Dictionary.c
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_Dictionary.c"
+
+static int *
+_keyNewInt(int key)
+{
+ int *newKey = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL",
+ sizeof(int));
+ *newKey = key;
+ return newKey;
+}
+
+static int *
+_valueNewInt(int value)
+{
+ int *newValue = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ *newValue = value;
+ return newValue;
+}
+
+static bool
+_valueEquals(const void *value1, const void *value2)
+{
+ return *(int *) value1 == *(int *) value2;
+}
+
+static int
+_intKeyComp(const void *key1, const void *key2)
+{
+ if (*(int *) key1 < *(int *) key2) {
+ return -1;
+ }
+ if (*(int *) key1 == *(int *) key2) {
+ return 0;
+ }
+ return 1;
+}
+
+static uint32_t
+_intKeyHash(const void *key1)
+{
+ return *(int *) key1;
+}
+
+
+static void
+_keyFree(void **value)
+{
+ parcMemory_Deallocate((void **) value);
+ *value = NULL;
+}
+
+static void
+_valueFree(void **key)
+{
+ parcMemory_Deallocate((void **) key);
+ *key = NULL;
+}
+
+
+
+
+LONGBOW_TEST_RUNNER(PARC_Dictionary)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_Dictionary)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_Dictionary)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(-1);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Create);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_SetValue_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_AfterDelete);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_AfterOverwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_EmptyTree);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Keys);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Create)
+{
+ PARCDictionary *dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, NULL, NULL, NULL);
+
+ parcDictionary_Destroy(&dictionary);
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_SetValue_Destroy)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(1), (void *) _valueNewInt(11));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(12));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(13));
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_Empty)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ assertTrue(0 == parcDictionary_Size(dictionary), "Wrong size of dictionary - empty, start");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008));
+
+ assertTrue(4 == parcDictionary_Size(dictionary), "Wrong size of dictionary after add 3");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_AfterDelete)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008));
+
+ int searchKey = 2;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary, &searchKey);
+
+ size_t size = parcDictionary_Size(dictionary);
+
+ assertTrue(3 == size, "Wrong size of dictionary after 1 delete (%zu instead of 3)", size);
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_AfterOverwrite)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008));
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1010));
+
+ size_t size = parcDictionary_Size(dictionary);
+
+ assertTrue(4 == size, "Wrong size of dictionary after 1 delete (%zu instead of 4)", size);
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_EmptyTree)
+{
+ PARCDictionary *dictionary;
+
+ int key = 100;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ void *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_NonExistent)
+{
+ PARCDictionary *dictionary;
+ int key = 100;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ void *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_First)
+{
+ PARCDictionary *dictionary;
+ int key = 1;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertNotNull(value, "NULL value returned");
+ assertTrue(*value == (1 << 8), "Wrong object returned or not found");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get)
+{
+ PARCDictionary *dictionary;
+ int key = 5;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertNotNull(value, "NULL value returned");
+ assertTrue(*value == (5 << 8), "Wrong object returned or not found");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_Last)
+{
+ PARCDictionary *dictionary;
+ int key = 9;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertNotNull(value, "NULL value returned");
+ assertTrue(*value == (9 << 8), "Wrong object returned or not found");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove_First)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(1), (void *) _valueNewInt(1 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 1;
+
+ void *data = parcDictionary_RemoveValue(dictionary1, &searchKey);
+
+ _valueFree(&data);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(30), (void *) _valueNewInt(31 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 30;
+
+ void *data = parcDictionary_RemoveValue(dictionary1, &searchKey);
+
+ _valueFree(&data);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove_Last)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(100), (void *) _valueNewInt(100 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 100;
+
+ void *data = parcDictionary_RemoveValue(dictionary1, &searchKey);
+
+ _valueFree(&data);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_First)
+{
+ PARCDictionary *dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ PARCDictionary *dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(1), (void *) _valueNewInt(1 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 1;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(30), (void *) _valueNewInt(31 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 30;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_Last)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(100), (void *) _valueNewInt(100 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 100;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Keys)
+{
+ PARCDictionary *dictionary =
+ parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 0; i < 9; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ PARCArrayList *keys = parcDictionary_Keys(dictionary);
+
+ assertNotNull(keys,
+ "parcDictionary_Keys returned NULL, expected non-NULL.");
+
+ assertTrue(parcArrayList_Size(keys) == parcDictionary_Size(dictionary),
+ "Expected parcDictionary_Keys size %zu, actual %zd, ",
+ parcDictionary_Size(dictionary), parcArrayList_Size(keys));
+
+ for (int i = 0; i < 9; i++) {
+ bool found = false;
+ int *keyToFind = _keyNewInt(i);
+ for (int j = 0; j < parcArrayList_Size(keys); j++) {
+ int *keyToTest = parcArrayList_Get(keys, j);
+ if (*keyToTest == *keyToFind) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found, "Expected to find Key %d, not found", *keyToFind);
+ parcMemory_Deallocate((void **) &keyToFind);
+ }
+ parcArrayList_Destroy(&keys);
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Values)
+{
+ PARCDictionary *dictionary =
+ parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 0; i < 9; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ PARCArrayList *values = parcDictionary_Values(dictionary);
+
+ assertNotNull(values,
+ "parcDictionary_Values returned NULL, expected not NULL");
+
+ assertTrue(parcArrayList_Size(values) == parcDictionary_Size(dictionary),
+ "parcDictionary_Values size %zd not equal not parcDictionary_Size, %zd",
+ parcArrayList_Size(values), parcDictionary_Size(dictionary));
+
+ for (int i = 0; i < 9; i++) {
+ bool found = false;
+ int *keyToFind = _keyNewInt(i);
+ int *valueToFind = parcDictionary_GetValue(dictionary, keyToFind);
+ for (int j = 0; j < parcArrayList_Size(values); j++) {
+ int *valueToTest = parcArrayList_Get(values, j);
+ if (valueToFind == valueToTest) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found,
+ "Expected to find value %d, not found", *valueToFind);
+ parcMemory_Deallocate((void **) &keyToFind);
+ }
+ parcArrayList_Destroy(&values);
+ parcDictionary_Destroy(&dictionary);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Empty)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Empty lists are not equal");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Values)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ int compareSetValues = 100;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ printf("Testing dictionary equals...\n");
+
+ for (int i = 1; i < compareSetValues; i++) {
+ parcDictionary_SetValue(dictionary1,
+ (void *) _keyNewInt(i),
+ (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2,
+ (void *) _keyNewInt(compareSetValues - i),
+ (void *) _valueNewInt((compareSetValues + i) << 8));
+ }
+
+ assertFalse(parcDictionary_Equals(dictionary1, dictionary2), "Dictionaries are equal and they shouldn't be!");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Keys)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ int compareSetValues = 100;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < compareSetValues; i++) {
+ parcDictionary_SetValue(dictionary1,
+ (void *) _keyNewInt(i),
+ (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2,
+ (void *) _keyNewInt(compareSetValues + i),
+ (void *) _valueNewInt((compareSetValues - i) << 8));
+ }
+
+ assertFalse(parcDictionary_Equals(dictionary1, dictionary2), "Lists are equal");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ int compareSetValues = 100;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < compareSetValues; i++) {
+ parcDictionary_SetValue(dictionary1,
+ (void *) _keyNewInt(i),
+ (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2,
+ (void *) _keyNewInt(compareSetValues - i),
+ (void *) _valueNewInt((compareSetValues - i) << 8));
+ }
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Dictionaries are not equal");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_Dictionary);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Display.c b/libparc/parc/algol/test/test_parc_Display.c
new file mode 100755
index 00000000..29b9fdf2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Display.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_DisplayIndented.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Display)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Display)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Display)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDisplay_PrintLine);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcDisplay_PrintLine)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Display);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Environment.c b/libparc/parc/algol/test/test_parc_Environment.c
new file mode 100755
index 00000000..e4513b31
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Environment.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Environment.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Environment)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Environment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Environment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcEnvironment_GetHomeDirectory);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcEnvironment_GetHomeDirectory)
+{
+ const char *homeDirectory = parcEnvironment_GetHomeDirectory();
+ assertNotNull(homeDirectory, "Cannot get the current home directory.");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Environment);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Event.c b/libparc/parc/algol/test/test_parc_Event.c
new file mode 100644
index 00000000..261cd079
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Event.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Event.c"
+
+LONGBOW_TEST_RUNNER(parc_Event)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Event)
+{
+ parcEvent_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Event)
+{
+ parcEvent_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Start);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Poll);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_SetPriority);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int _test_event_called = 0;
+
+static void
+_test_event(int fd, PARCEventType flags, void *data)
+{
+ _test_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Create_Destroy)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write, _test_event, NULL);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Start)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Read | PARCEventType_Write, _test_event, NULL);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+
+ _test_event_called = 0;
+ parcEvent_Start(parcEvent);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+static int _test_stop_event_called = 0;
+
+static void
+_test_stop_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEvent **parcEvent = (PARCEvent **) data;
+ _test_stop_event_called++;
+ parcEvent_Stop(*parcEvent);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Stop)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write | PARCEventType_Persist, _test_stop_event, &parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+
+ parcEvent_Start(parcEvent);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_stop_event_called > 0, "Event never called.");
+ assertFalse(_test_stop_event_called != 1, "Event called more than once.");
+
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Poll)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write, _test_event, NULL);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+
+ result = parcEvent_Poll(parcEvent, PARCEventType_Read);
+ // should be no outstanding events
+ assertTrue(result == 0, "parcEvent_Poll returned %d\n", result);
+
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+static int _test_writeMaxPriority_event_called = 0;
+
+static void
+_test_writeMaxPriority_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEvent *parcEvent = *((PARCEvent **) data);
+ parcEvent_Stop(parcEvent);
+ _test_writeMaxPriority_event_called++;
+}
+
+static int _test_writeMinPriority_event_called = 0;
+
+static void
+_test_writeMinPriority_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEvent *parcEvent = *((PARCEvent **) data);
+ parcEvent_Stop(parcEvent);
+ _test_writeMinPriority_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_SetPriority)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ //
+ // First event to be called back disables its partner's event
+ //
+ PARCEvent *parcEventWriteMax, *parcEventWriteMin;
+ parcEventWriteMax = parcEvent_Create(parcEventScheduler, fds[0],
+ PARCEventType_Write,
+ _test_writeMaxPriority_event,
+ (void *) &parcEventWriteMin);
+ assertNotNull(parcEventWriteMax, "parcEvent_Create returned a null reference");
+ parcEventWriteMin = parcEvent_Create(parcEventScheduler, fds[1],
+ PARCEventType_Write,
+ _test_writeMinPriority_event,
+ (void *) &parcEventWriteMax);
+ assertNotNull(parcEventWriteMin, "parcEvent_Create returned a null reference");
+
+ result = parcEvent_SetPriority(parcEventWriteMin, PARCEventPriority_Minimum);
+ assertTrue(result == 0, "parcEvent_SetPriority write returned %d\n", result);
+ result = parcEvent_SetPriority(parcEventWriteMax, PARCEventPriority_Maximum);
+ assertTrue(result == 0, "parcEvent_SetPriority read returned %d\n", result);
+
+ parcEvent_Start(parcEventWriteMin);
+ parcEvent_Start(parcEventWriteMax);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking);
+
+ assertTrue(_test_writeMaxPriority_event_called == 1, "Read event called before priority write event handled");
+ assertTrue(_test_writeMinPriority_event_called == 0, "Write event never triggered");
+
+ parcEvent_Destroy(&parcEventWriteMax);
+ parcEvent_Destroy(&parcEventWriteMin);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Event);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventBuffer.c b/libparc/parc/algol/test/test_parc_EventBuffer.c
new file mode 100644
index 00000000..c0b8d8c9
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventBuffer.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventBuffer.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventBuffer.c"
+
+LONGBOW_TEST_RUNNER(parc_EventBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_EventBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_GetLength_Append);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Prepend_Pullup);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadIntoBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_AppendBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Read);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_WriteToFileDescriptor);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadFromFileDescriptor);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadLine_FreeLine);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_GetQueueBuffer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ parcEventBuffer_DisableDebug();
+}
+
+static int _dataLength = 8192;
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_GetLength_Append)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char data[_dataLength];
+ parcEventBuffer_Append(parcEventBuffer, data, _dataLength);
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == _dataLength, "Buffer length does not match length of appended data");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static uint8_t prependedDataValue = '1';
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_Prepend_Pullup)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char data[_dataLength];
+ data[0] = 2;
+ parcEventBuffer_Append(parcEventBuffer, data, _dataLength);
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == _dataLength, "Buffer length does not match length of appended data");
+
+ uint8_t prependedData[1];
+ prependedData[0] = prependedDataValue;
+ parcEventBuffer_Prepend(parcEventBuffer, prependedData, sizeof(uint8_t));
+ size_t bufferSize = parcEventBuffer_GetLength(parcEventBuffer);
+ assertTrue(bufferSize == (_dataLength + 1), "Buffer length does not match length plus prepended data length");
+
+ uint8_t *completeBuffer = parcEventBuffer_Pullup(parcEventBuffer, -1);
+ assertTrue(completeBuffer[0] == prependedDataValue, "Prepended data doesn't match %d != %d", completeBuffer[0], prependedDataValue);
+ assertTrue(completeBuffer[1] == 2, "Consolidated data doesn't match %d != %d", completeBuffer[1], 2);
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadIntoBuffer)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBufferSource = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferSource, "parcEventBuffer_Create returned a null reference");
+ char sourceData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferSource, sourceData, _dataLength);
+
+ PARCEventBuffer *parcEventBufferDestination = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferDestination, "parcEventBuffer_Create returned a null reference");
+ char destinationData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferDestination, destinationData, _dataLength);
+
+ parcEventBuffer_ReadIntoBuffer(parcEventBufferSource, parcEventBufferDestination, -1);
+ size_t bufferSize = parcEventBuffer_GetLength(parcEventBufferDestination);
+ assertTrue(bufferSize == (_dataLength * 2), "Destination buffer size doesn't match expected length");
+
+ parcEventBuffer_Destroy(&parcEventBufferSource);
+ parcEventBuffer_Destroy(&parcEventBufferDestination);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_AppendBuffer)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBufferSource = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferSource, "parcEventBuffer_Create returned a null reference");
+ char sourceData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferSource, sourceData, _dataLength);
+
+ PARCEventBuffer *parcEventBufferDestination = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferDestination, "parcEventBuffer_Create returned a null reference");
+ char destinationData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferDestination, destinationData, _dataLength);
+
+ parcEventBuffer_AppendBuffer(parcEventBufferSource, parcEventBufferDestination);
+ size_t bufferSize = parcEventBuffer_GetLength(parcEventBufferDestination);
+ assertTrue(bufferSize == (_dataLength * 2), "Destination buffer size doesn't match expected length, %zu != %d", bufferSize, _dataLength * 2);
+
+ parcEventBuffer_Destroy(&parcEventBufferSource);
+ parcEventBuffer_Destroy(&parcEventBufferDestination);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_Read)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[64] = "This is a test";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+
+ char readDataBuffer[64];
+ int length = parcEventBuffer_Read(parcEventBuffer, readDataBuffer, 32);
+
+ assertTrue(strncmp(sourceData, readDataBuffer, 32) == 0,
+ "Buffer contents written do not match contents read");
+ assertTrue(length == 32, "parcEventBuffer_Read length unexpected %d != 32\n", length);
+
+ length = parcEventBuffer_Read(parcEventBuffer, NULL, 64);
+ assertTrue(length == 0, "Drain of parcEventBuffer returned %d", length);
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_WriteToFileDescriptor)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[100] = "This is a test";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+ size_t written = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fds[0], 64);
+
+ assertTrue(written == 64, "Length written does not match buffer length.");
+ assertTrue(read(fds[1], sourceData, 100) == 64, "Length read does not match length written.");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadFromFileDescriptor)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[64] = "This is a test";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+
+ size_t written = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fds[0], 64);
+ assertTrue(written == 64, "Length written does not match buffer length.");
+ size_t read = parcEventBuffer_ReadFromFileDescriptor(parcEventBuffer, fds[1], -1);
+
+ assertTrue(read == 64, "Length read does not match amount written.");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadLine_FreeLine)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[64] = "This is a test\n";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == 64, "parcEventBuffer has wrong length %zu.", parcEventBuffer_GetLength(parcEventBuffer));
+
+ size_t bytesRead;
+ char *lineRead = parcEventBuffer_ReadLine(parcEventBuffer, &bytesRead);
+ // read up to newline and terminate, so we read the newline but don't return it in the result
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == (64 - (bytesRead + 1)),
+ "parcEventBuffer has wrong length %zu != %zu.",
+ (64 - (bytesRead + 1)), parcEventBuffer_GetLength(parcEventBuffer));
+ assertTrue(strncmp(sourceData, lineRead, bytesRead) == 0, "Line read doesn't match %s != %s", sourceData, lineRead);
+ assertTrue((strlen(sourceData) - strlen(lineRead)) == 1, "Line length doesn't match %zu != %zu", strlen(sourceData), strlen(lineRead));
+
+ parcEventBuffer_FreeLine(parcEventBuffer, &lineRead);
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_GetQueueBuffer)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, fds[0], 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ PARCEventBuffer *parcEventBuffer_Output = parcEventBuffer_GetQueueBufferOutput(parcEventQueue);
+ assertNotNull(parcEventBuffer_Output, "Received null output buffer from queue");
+
+ PARCEventBuffer *parcEventBuffer_Input = parcEventBuffer_GetQueueBufferInput(parcEventQueue);
+ assertNotNull(parcEventBuffer_Input, "Received null input buffer from queue");
+
+ parcEventBuffer_Destroy(&parcEventBuffer_Output);
+ parcEventBuffer_Destroy(&parcEventBuffer_Input);
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventBuffer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventQueue.c b/libparc/parc/algol/test/test_parc_EventQueue.c
new file mode 100644
index 00000000..862cb61d
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventQueue.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventQueue.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventQueue.c"
+
+LONGBOW_TEST_RUNNER(parc_EventQueue)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_EventQueue)
+{
+ parcEventQueue_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventQueue)
+{
+ parcEventQueue_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetFileDescriptor_GetFileDecriptor);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Get_Enable_Disable);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetCallbacks);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Flush);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Finished);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetWatermark);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_ReadWrite);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetPriority);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Printf);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_GetEvBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_ConnectSocket);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Create_Destroy_Pair);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_GetUpDownQueue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ assertNull(parcEventQueue, "parcEventQueue_Destroy did not clear reference");
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ assertNull(parcEventScheduler, "parcEventScheduler_Destroy did not clear reference");
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Get_Enable_Disable)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ PARCEventType defaultEvents = parcEventQueue_GetEnabled(parcEventQueue);
+
+ parcEventQueue_Enable(parcEventQueue, PARCEventType_Read);
+ PARCEventType newEvents = parcEventQueue_GetEnabled(parcEventQueue);
+ assertTrue(newEvents == (defaultEvents | PARCEventType_Read),
+ "parcEventQueue_GetEnabled returned incorrect event set 0x%x != 0x%x",
+ newEvents, defaultEvents | PARCEventType_Read);
+
+ parcEventQueue_Disable(parcEventQueue, PARCEventType_Read);
+
+ newEvents = parcEventQueue_GetEnabled(parcEventQueue);
+ assertTrue(defaultEvents == newEvents, "parcEventQueue_GetEnabled returned incorrect event set 0x%x != 0x%x", newEvents, defaultEvents);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetFileDescriptor_GetFileDecriptor)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned null");
+
+ result = parcEventQueue_SetFileDescriptor(parcEventQueue, fds[0]);
+ assertTrue(result == 0, " parcEventQueue_SetFileDescriptor call failed");
+
+ result = parcEventQueue_GetFileDescriptor(parcEventQueue);
+ assertTrue(result == fds[0], "parcEventQueue_GetFileDescriptor failed");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Create_Destroy_Pair)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned null");
+
+ PARCEventQueuePair *parcEventQueuePair = parcEventQueue_CreateConnectedPair(parcEventScheduler);
+ assertNotNull(parcEventQueuePair, "parcEventQueue_CreateConnectedPair returned a null pair");
+
+ parcEventQueue_DestroyConnectedPair(&parcEventQueuePair);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_GetUpDownQueue)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+
+ PARCEventQueuePair *parcEventQueuePair = parcEventQueue_CreateConnectedPair(parcEventScheduler);
+
+ assertNotNull(parcEventQueue_GetConnectedUpQueue(parcEventQueuePair), "parcEventQueue_GetUpQueue returned null");
+ assertNotNull(parcEventQueue_GetConnectedDownQueue(parcEventQueuePair), "parcEventQueue_GetDownQueue returned null");
+
+ parcEventQueue_DestroyConnectedPair(&parcEventQueuePair);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static int _queue_callback_count = 0;
+
+static void
+_queue_callback(PARCEventQueue *event, PARCEventType type, void *data)
+{
+ _queue_callback_count++;
+}
+
+static int _queue_event_callback_count = 0;
+
+static void
+_queue_event_callback(PARCEventQueue *event, PARCEventQueueEventType type, void *data)
+{
+ _queue_event_callback_count++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetCallbacks)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ parcEventQueue_SetCallbacks(parcEventQueue,
+ _queue_callback,
+ _queue_callback,
+ _queue_event_callback,
+ NULL);
+
+ _parc_queue_read_callback(NULL, parcEventQueue);
+ assertTrue(_queue_callback_count == 1, "Callback count expected 1 got %d", _queue_callback_count);
+
+ _parc_queue_write_callback(NULL, parcEventQueue);
+ assertTrue(_queue_callback_count == 2, "Callback count expected 2 got %d", _queue_callback_count);
+
+ _parc_queue_event_callback(NULL, PARCEventQueueEventType_EOF, parcEventQueue);
+ assertTrue(_queue_event_callback_count == 1, "Callback event count expected 1 got %d", _queue_event_callback_count);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Flush)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ int result = parcEventQueue_Flush(parcEventQueue, PARCEventType_Read);
+ assertTrue(result == 0, "parcEventQueue_Flush failed with %d", result);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Finished)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ int result = parcEventQueue_Finished(parcEventQueue, PARCEventType_Read);
+ assertTrue(result == 0, "parcEventQueue_Finished failed with %d", result);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetWatermark)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ parcEventQueue_SetWatermark(parcEventQueue, PARCEventType_Read, 0, 0);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_ReadWrite)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ char *data = "Hello World\n";
+ int length = strlen(data);
+ int result = parcEventQueue_Write(parcEventQueue, data, length);
+ assertTrue(result == 0, "parcEventQueue_Write failed.");
+
+ char buffer[64];
+ result = parcEventQueue_Read(parcEventQueue, buffer, 64);
+ assertTrue(result == 0, "parcEventQueue_Read failed.");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static int _test_writeMaxPriority_event_called = 0;
+static void
+_test_writeMaxPriority_callback(PARCEventQueue *parcEventQueue, PARCEventType event, void *data)
+{
+ PARCEventQueue *parcEventQueuePartner = *((PARCEventQueue **) data);
+ parcEventQueue_Disable(parcEventQueuePartner, event);
+ _test_writeMaxPriority_event_called++;
+}
+
+static int _test_writeMinPriority_event_called = 0;
+static void
+_test_writeMinPriority_callback(PARCEventQueue *parcEventQueue, PARCEventType event, void *data)
+{
+ PARCEventQueue *parcEventQueuePartner = *((PARCEventQueue **) data);
+ parcEventQueue_Disable(parcEventQueuePartner, event);
+ _test_writeMinPriority_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetPriority)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ //
+ // First queue to be called back disables its partner's queue
+ //
+ PARCEventQueue *parcEventQueueMin, *parcEventQueueMax;
+ parcEventQueueMin = parcEventQueue_Create(parcEventScheduler, fds[0], PARCEventQueueOption_CloseOnFree);
+ assertNotNull(parcEventQueueMin, "parcEventQueue_Create returned a null reference");
+ parcEventQueue_SetCallbacks(parcEventQueueMin, NULL, _test_writeMinPriority_callback, NULL, (void *) &parcEventQueueMax);
+
+ parcEventQueueMax = parcEventQueue_Create(parcEventScheduler, fds[0], PARCEventQueueOption_CloseOnFree);
+ assertNotNull(parcEventQueueMax, "parcEventQueue_Create returned a null reference");
+ parcEventQueue_SetCallbacks(parcEventQueueMax, NULL, _test_writeMaxPriority_callback, NULL, (void *) &parcEventQueueMin);
+
+ result = parcEventQueue_SetPriority(parcEventQueueMin, PARCEventPriority_Minimum);
+ assertTrue(result == 0, "parcEventQueue_SetPriority Minimum priority failed.");
+ result = parcEventQueue_SetPriority(parcEventQueueMax, PARCEventPriority_Maximum);
+ assertTrue(result == 0, "parcEventQueue_SetPriority Maximum priority failed.");
+
+ parcEventQueue_Enable(parcEventQueueMin, PARCEventType_Write);
+ parcEventQueue_Enable(parcEventQueueMax, PARCEventType_Write);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking);
+
+ assertTrue(_test_writeMaxPriority_event_called == 1, "Read event called before priority write event handled");
+ assertTrue(_test_writeMinPriority_event_called == 0, "Write event never triggered");
+
+ parcEventQueue_Destroy(&parcEventQueueMin);
+ parcEventQueue_Destroy(&parcEventQueueMax);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Printf)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ int result = parcEventQueue_Printf(parcEventQueue, "%s %s\n", "Hello", "World");
+ assertTrue(result == 12, "parcEventQueue_Printf didn't write expected length %d != %d", result, 12);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_GetEvBuffer)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ struct evbuffer *result = internal_parcEventQueue_GetEvInputBuffer(parcEventQueue);
+ assertTrue(result != NULL, "parcEventQueue_GetEvInputBuffer failed.");
+
+ result = internal_parcEventQueue_GetEvOutputBuffer(parcEventQueue);
+ assertTrue(result != NULL, "parcEventQueue_GetEvOutputBuffer failed.");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_ConnectSocket)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, -1, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ struct sockaddr_in address;
+ int addressLength = sizeof(address);
+ memset(&address, 0, addressLength);
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ address.sin_port = htons(8080); /* Port 8080 */
+
+ int result = parcEventQueue_ConnectSocket(parcEventQueue, (struct sockaddr *) &address, addressLength);
+ assertTrue(result == 0, "parcEventQueue_ConnectSocket returned %d", result);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventQueue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventScheduler.c b/libparc/parc/algol/test/test_parc_EventScheduler.c
new file mode 100755
index 00000000..8195bd2e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventScheduler.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <pthread.h>
+
+#include <LongBow/unit-test.h>
+
+#include "../internal_parc_Event.h"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventTimer.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventScheduler.c"
+
+LONGBOW_TEST_RUNNER(parc_EventScheduler)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_EventScheduler)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventScheduler)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Run);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Dispatch);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Abort);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Memory);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_GetEvBase);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_GetLogger);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcEventScheduler_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ parcEventScheduler_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ assertNull(parcEventScheduler, "parcEventScheduler_Destroy failed to null reference");
+}
+
+static void
+_event_callback(int fd, PARCEventType flags, void *data)
+{
+ (*(unsigned *) data)++;
+}
+
+static int _callback_event_called = 0;
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Run)
+{
+ _callback_event_called = 0;
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, 0, _event_callback, (void *) &_callback_event_called);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 0, 1 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_callback_event_called == 1, "Timer event never called back");
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Dispatch)
+{
+ _callback_event_called = 0;
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, 0, _event_callback, (void *) &_callback_event_called);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 0, 1 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ // This will block until the event is processed
+ parcEventScheduler_DispatchBlocking(parcEventScheduler);
+ assertTrue(_callback_event_called == 1, "Timer event never called back");
+
+ // Start the timer
+ struct timeval longerfs = { 1, 0 }; // 1s
+ parcEventTimer_Start(parcEvent, &longerfs);
+ parcEventScheduler_DispatchNonBlocking(parcEventScheduler);
+ assertTrue(_callback_event_called == 1, "Timer event called again prematurely");
+ usleep(2000000); // 2s
+ parcEventScheduler_DispatchNonBlocking(parcEventScheduler);
+ assertTrue(_callback_event_called == 2, "Timer event never called back");
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_stop_callback(int fd, PARCEventType flags, void *data)
+{
+ PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data;
+ struct timeval fs = { 0, 0 };
+ parcEventScheduler_Stop(parcEventScheduler, &fs);
+ _callback_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Stop)
+{
+ _callback_event_called = 0;
+
+ // Create a new scheduler
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ // Create a persistent event which will repeat until stopped
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, PARCEventType_Persist, _stop_callback, parcEventScheduler);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 1, 0 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_callback_event_called == 1, "Timer event never called back");
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_abort_callback(int fd, PARCEventType flags, void *data)
+{
+ PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data;
+ parcEventScheduler_Abort(parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Abort)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, PARCEventType_Persist, _abort_callback, parcEventScheduler);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 1, 0 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_test_memory_event(int fd, short flags, void *data)
+{
+}
+
+/**
+ * Ensure that the scheduler is using parc memory inside libevent
+ */
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Memory)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ size_t baseline = parcMemory_Outstanding();
+
+ struct event *testEvent = event_new(parcEventScheduler_GetEvBase(parcEventScheduler), -1, 0, _test_memory_event, NULL);
+
+ assertTrue(parcMemory_Outstanding() > baseline,
+ "event_new() did not increase parcMemory_Outstanding: baseline %zu now %u",
+ baseline,
+ parcMemory_Outstanding());
+
+ event_free(testEvent);
+
+ assertTrue(parcMemory_Outstanding() == baseline,
+ "event_free() did reduce to baseline: baseline %zu now %u",
+ baseline,
+ parcMemory_Outstanding());
+
+ parcEventScheduler_Destroy(&parcEventScheduler);
+
+ assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_GetEvBase)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ assertNotNull(parcEventScheduler_GetEvBase(parcEventScheduler), "Expected a non-null EV pointer.");
+
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_GetLogger)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ assertNotNull(parcEventScheduler_GetLogger(parcEventScheduler), "Expected a non-null logger.");
+
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventScheduler);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventSignal.c b/libparc/parc/algol/test/test_parc_EventSignal.c
new file mode 100644
index 00000000..fcb86333
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventSignal.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventSignal.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventSignal.c"
+
+LONGBOW_TEST_RUNNER(parc_EventSignal)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_EventSignal)
+{
+ parcEventSignal_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventSignal)
+{
+ parcEventSignal_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventSignal_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventSignal_Start_Stop);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int _empty_event_called = 0;
+
+static void
+_empty_event(int fd, PARCEventType flags, void *data)
+{
+ _empty_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSignal_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _empty_event, NULL);
+ assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference");
+
+ _parc_event_signal_callback(0, 0, (void *) parcEventSignal);
+ assertTrue(_empty_event_called == 1, "Event handler never called.");
+ parcEventSignal_Destroy(&parcEventSignal);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+#include <pthread.h>
+
+static void *
+_run_scheduler(void *data)
+{
+ PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data;
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ return NULL;
+}
+
+static int _test_event_called = 0;
+
+static void
+_signal_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEventSignal **parcEventSignal = (PARCEventSignal **) data;
+ _test_event_called++;
+ parcEventSignal_Stop(*parcEventSignal);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSignal_Start_Stop)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _signal_event, &parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference");
+
+ parcEventSignal_Start(parcEventSignal);
+
+ pthread_t thread;
+ pthread_create(&thread, NULL, _run_scheduler, parcEventScheduler);
+
+ kill(getpid(), SIGUSR1);
+ pthread_join(thread, NULL);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventSignal_Destroy(&parcEventSignal);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_test_stop_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEventSignal **parcEventSignal = (PARCEventSignal **) data;
+ _test_event_called++;
+ parcEventSignal_Stop(*parcEventSignal);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSignal_Stop)
+{
+ _test_event_called = 0;
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _test_stop_event, &parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference");
+
+ parcEventSignal_Start(parcEventSignal);
+ kill(getpid(), SIGUSR1);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventSignal_Destroy(&parcEventSignal);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventSignal);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventSocket.c b/libparc/parc/algol/test/test_parc_EventSocket.c
new file mode 100644
index 00000000..dbe8892b
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventSocket.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventSocket.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventSocket.c"
+
+LONGBOW_TEST_RUNNER(parc_EventSocket)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_EventSocket)
+{
+ parcEventSocket_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventSocket)
+{
+ parcEventSocket_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventSocket_Create_Destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int _test_event_called = 0;
+
+static void
+listener_callback(int fd, struct sockaddr *sa, int socklen, void *user_data)
+{
+ _test_event_called++;
+}
+
+static int _test_error_event_called = 0;
+
+static void
+listener_error_callback(PARCEventScheduler *base, int error, char *errorString, void *addr_unix)
+{
+ _test_error_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSocket_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(49009);
+ inet_pton(AF_INET, "127.0.0.1", &(addr.sin_addr));
+
+ PARCEventSocket *parcEventSocket = parcEventSocket_Create(parcEventScheduler,
+ listener_callback,
+ listener_error_callback,
+ NULL, NULL, 0);
+ assertNull(parcEventSocket, "parcEventSocket_Create didn't return an error when expected");
+
+ parcEventSocket = parcEventSocket_Create(parcEventScheduler,
+ listener_callback,
+ listener_error_callback,
+ NULL, (struct sockaddr *) &addr, sizeof(addr));
+ assertNotNull(parcEventSocket, "parcEventSocket_Create returned a null reference");
+
+ _parc_evconn_callback(NULL, 0, (struct sockaddr *) &addr, sizeof(addr), parcEventSocket);
+ assertTrue(_test_event_called == 1, "Listener callback wasn't triggered");
+ _parc_evconn_error_callback(NULL, parcEventSocket);
+ assertTrue(_test_error_event_called == 1, "Listener error callback wasn't triggered");
+
+ parcEventSocket_Destroy(&parcEventSocket);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventSocket);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventTimer.c b/libparc/parc/algol/test/test_parc_EventTimer.c
new file mode 100755
index 00000000..f6b9917e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventTimer.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventTimer.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventTimer.c"
+
+LONGBOW_TEST_RUNNER(parc_EventTimer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_EventTimer)
+{
+ parcEventTimer_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventTimer)
+{
+ parcEventTimer_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Start);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Stop);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int _test_event_called = 0;
+
+static void
+_test_event(int fd, PARCEventType flags, void *data)
+{
+ _test_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventTimer_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None, _test_event, NULL);
+ assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference");
+
+ parcEventTimer_Destroy(&parcEventTimer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventTimer_Start)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None, _test_event, NULL);
+ assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference");
+
+ struct timeval timeout = { 1, 0 };
+ parcEventTimer_Start(parcEventTimer, &timeout);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventTimer_Destroy(&parcEventTimer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_test_stop_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEventTimer **parcEventTimer = (PARCEventTimer **) data;
+ _test_event_called++;
+ parcEventTimer_Stop(*parcEventTimer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventTimer_Stop)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None | PARCEventType_Persist, _test_stop_event, &parcEventTimer);
+ assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference");
+
+ _test_event_called = 0;
+ struct timeval timeout = { 1, 0 };
+ parcEventTimer_Start(parcEventTimer, &timeout);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventTimer_Destroy(&parcEventTimer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventTimer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_File.c b/libparc/parc/algol/test/test_parc_File.c
new file mode 100644
index 00000000..eccef210
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_File.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+#include <fcntl.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SafeMemory.h"
+#include "../parc_File.c"
+
+#define PATH_SEGMENT "A"
+
+LONGBOW_TEST_RUNNER(parc_File)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_File)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_File)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFile_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ longBowClipBoard_SetInt(testClipBoard, "initalAllocations", parcMemory_Outstanding());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ uint64_t initialAllocations = longBowClipBoard_GetAsInt(testClipBoard, "initalAllocations");
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (initialAllocations < outstandingAllocations) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFile_AcquireRelease)
+{
+ char *root = "/tmp/test_parc_File";
+
+ PARCFile *file = parcFile_Create(root);
+
+ PARCFile *reference = parcFile_Acquire(file);
+
+ parcFile_Release(&reference);
+
+ parcFile_AssertValid(file);
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateChild);
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateDeleteNewFile);
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateDelete_Directory);
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_Exists);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowClipBoard_SetInt(testClipBoard, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint64_t initialAllocations = longBowClipBoard_GetAsInt(testClipBoard, "initalAllocations");
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (initialAllocations < outstandingAllocations) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_Exists)
+{
+ char *root = "/tmp";
+
+ PARCFile *parent = parcFile_Create(root);
+
+ char *child = "foo";
+ PARCFile *file = parcFile_CreateChild(parent, child);
+
+ parcFile_CreateNewFile(file);
+
+ bool actual = parcFile_Exists(file);
+
+ assertTrue(actual, "Expected the file to exist.");
+
+ parcFile_Release(&file);
+ parcFile_Release(&parent);
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_CreateChild)
+{
+ char *root = "/tmp";
+
+ PARCFile *parent = parcFile_Create(root);
+
+ char *child = "foo";
+ PARCFile *file = parcFile_CreateChild(parent, child);
+
+ char *actual = parcFile_ToString(file);
+
+ assertTrue(strcmp("/tmp/foo", actual) == 0,
+ "Expected %s, actual %s", "/tmp/foo", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcFile_Release(&file);
+ parcFile_Release(&parent);
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_CreateDeleteNewFile)
+{
+ char *name = "/tmp/test_parc_File";
+
+ PARCFile *file = parcFile_Create(name);
+
+ parcFile_CreateNewFile(file);
+
+ bool actual = parcFile_Delete(file);
+ assertTrue(actual, "Expected parcFile_Delete to return true.");
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_CreateDelete_Directory)
+{
+ char *name = "/tmp/test_parc_File_directory";
+
+ PARCFile *directory = parcFile_Create(name);
+
+ parcFile_Mkdir(directory);
+
+ char *fileName = "foo";
+ PARCFile *file = parcFile_CreateChild(directory, fileName);
+
+ bool success = parcFile_CreateNewFile(file);
+ assertTrue(success, "Expected parcFile_CreateNewFile success");
+
+ bool actual = parcFile_Delete(directory);
+ assertTrue(actual, "Expected parcFile_Delete to return true.");
+
+ parcFile_Release(&file);
+ parcFile_Release(&directory);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_File);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_FileChunker.c b/libparc/parc/algol/test/test_parc_FileChunker.c
new file mode 100755
index 00000000..6060cff6
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_FileChunker.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_FileChunker.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferChunker.h>
+
+LONGBOW_TEST_RUNNER(parc_FileChunker)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_FileChunker)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_FileChunker)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_CreateFromFile);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_File);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_FilePartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_FileSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_File);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_FilePartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_FileSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+_createFile(char *fname, PARCBuffer *buffer)
+{
+ PARCFile *file = parcFile_Create(fname);
+ if (!parcFile_Exists(file)) {
+ parcFile_CreateNewFile(file);
+ }
+ PARCRandomAccessFile *fhandle = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ parcRandomAccessFile_Write(fhandle, buffer);
+ parcRandomAccessFile_Close(fhandle);
+ parcRandomAccessFile_Release(&fhandle);
+}
+
+static void
+_deleteFile(char *fname)
+{
+ PARCFile *file = parcFile_Create(fname);
+ parcFile_Delete(file);
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_CreateFromFile)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ PARCFileChunker *copy = parcFileChunker_Acquire(chunker);
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+ assertNotNull(copy, "Expected non-NULL copy of Chunker");
+ parcFileChunker_Release(&copy);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_File)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_FilePartial)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_FileSmall)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 16; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 4096); // each chunk is 1024 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 16; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_File)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_FilePartial)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", (31 - count), i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_FileSmall)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize)
+{
+ size_t expectedChunkSize = 32;
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ PARCFileChunker *chunker = parcFileChunker_Create(file, expectedChunkSize); // each chunk is 32 bytes
+
+ size_t actualChunkSize = parcBufferChunker_GetChunkSize(chunker);
+
+ assertTrue(actualChunkSize == expectedChunkSize, "Expected chunk size of %zu, got %zu", expectedChunkSize, actualChunkSize);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_FileChunker);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_FileInputStream.c b/libparc/parc/algol/test/test_parc_FileInputStream.c
new file mode 100755
index 00000000..49032050
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_FileInputStream.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_FileInputStream.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(test_parc_FileInputStream)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_FileInputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_FileInputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcFileInputStream_Open);
+ LONGBOW_RUN_TEST_CASE(Global, parcFileInputStream_ReadFile);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcFileInputStream_Open)
+{
+ PARCFile *file = parcFile_Create("test_parc_FileInputStream");
+ PARCFileInputStream *stream = parcFileInputStream_Open(file);
+
+ parcFileInputStream_Release(&stream);
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Global, parcFileInputStream_ReadFile)
+{
+ PARCFile *file = parcFile_Create("test_parc_FileInputStream");
+ PARCFileInputStream *stream = parcFileInputStream_Open(file);
+
+ PARCBuffer *actual = parcFileInputStream_ReadFile(stream);
+ assertNotNull(actual, "Expected non-null result from parcFileInputStream_ReadFile");
+
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_HasRemaining(actual), "Expected the buffer to contain data.");
+
+ parcBuffer_Release(&actual);
+ parcFileInputStream_Release(&stream);
+ parcFile_Release(&file);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_FileInputStream);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_FileOutputStream.c b/libparc/parc/algol/test/test_parc_FileOutputStream.c
new file mode 100755
index 00000000..aa4236ae
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_FileOutputStream.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+#include <fcntl.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SafeMemory.h"
+#include "../parc_FileOutputStream.c"
+
+#define PATH_SEGMENT "A"
+
+LONGBOW_TEST_RUNNER(parc_FileOutputStream)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_FileOutputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_FileOutputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_Create);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_Release);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ unlink("/tmp/test_parc_FileOutputStream");
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_Create)
+{
+ PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+ assertNotNull(stream, "Expected a non-null pointer");
+
+ parcFileOutputStream_Release(&stream);
+ assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer");
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_Release)
+{
+ PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+ assertNotNull(stream, "Expected a non-null pointer");
+
+ parcFileOutputStream_Release(&stream);
+ assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer");
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_AcquireRelease)
+{
+ PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+ assertNotNull(stream, "Expected a non-null pointer");
+
+ PARCFileOutputStream *reference = parcFileOutputStream_Acquire(stream);
+ assertTrue(stream == reference, "Expected the reference to be equal to the original.");
+
+ parcFileOutputStream_Release(&stream);
+ assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer");
+
+ parcFileOutputStream_Release(&reference);
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcFileOutputStream_Write);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ unlink("/tmp/test_parc_FileOutputStream");
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcFileOutputStream_Write)
+{
+ PARCFileOutputStream *stream =
+ parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+
+ PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024 * 1024);
+
+ parcFileOutputStream_Write(stream, buffer);
+
+ assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy");
+
+ parcBuffer_Release(&buffer);
+
+ parcFileOutputStream_Release(&stream);
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_FileOutputStream);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Hash.c b/libparc/parc/algol/test/test_parc_Hash.c
new file mode 100755
index 00000000..cc92a867
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Hash.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_Hash.c"
+
+#include <LongBow/testing.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Hash)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Hash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Hash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Update);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_UpdateUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Hash);
+
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Data);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Int32);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Int64);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Data);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Int32);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Int64);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Update)
+{
+ PARCHash32Bits *hash = parcHash32Bits_Create();
+ parcHash32Bits_Update(hash, "123", 3);
+ uint32_t value = parcHash32Bits_Hash(hash);
+ assertTrue(value != 0, "Expected a non-zero (non-initial) value");
+
+ parcHash32Bits_Release(&hash);
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_UpdateUint32)
+{
+ PARCHash32Bits *hash = parcHash32Bits_Create();
+ parcHash32Bits_UpdateUint32(hash, 123);
+ uint32_t value = parcHash32Bits_Hash(hash);
+ assertTrue(value != 0, "Expected a non-zero (non-initial) value");
+
+ parcHash32Bits_Release(&hash);
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Hash)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash32_Data)
+{
+ char *data1 = "Hello World";
+ char *data2 = "Hello World1";
+ char *data3 = "Hello World2";
+
+ char data4[20];
+ strncpy(data4, data1, sizeof(data4));
+
+ uint32_t hash1 = parcHash32_Data(data1, strlen(data1));
+ uint32_t hash2 = parcHash32_Data(data2, strlen(data2));
+ uint32_t hash3 = parcHash32_Data(data3, strlen(data3));
+ uint32_t hash4 = parcHash32_Data(data4, strlen(data4));
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash4 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash1, "Hash collision, unlikely");
+ assertTrue(hash1 == hash4, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash32_Int32)
+{
+ uint32_t data1 = 12345;
+ uint32_t data2 = 12346;
+ uint32_t data3 = 12345;
+
+ uint32_t hash1 = parcHash32_Int32(data1);
+ uint32_t hash2 = parcHash32_Int32(data2);
+ uint32_t hash3 = parcHash32_Int32(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash32_Int64)
+{
+ uint64_t data1 = 10010010012345;
+ uint64_t data2 = 10010010012346;
+ uint64_t data3 = 10010010012345;
+
+ uint32_t hash1 = parcHash32_Int64(data1);
+ uint32_t hash2 = parcHash32_Int64(data2);
+ uint32_t hash3 = parcHash32_Int64(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash64_Data)
+{
+ char *data1 = "Hello World";
+ char *data2 = "Hello World1";
+ char *data3 = "Hello World2";
+
+ char data4[20];
+ strncpy(data4, data1, sizeof(data4));
+
+ uint64_t hash1 = parcHash64_Data(data1, strlen(data1));
+ uint64_t hash2 = parcHash64_Data(data2, strlen(data2));
+ uint64_t hash3 = parcHash64_Data(data3, strlen(data3));
+ uint64_t hash4 = parcHash64_Data(data4, strlen(data4));
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash4 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash1, "Hash collision, unlikely");
+ assertTrue(hash1 == hash4, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash64_Int32)
+{
+ uint32_t data1 = 12345;
+ uint32_t data2 = 12346;
+ uint32_t data3 = 12345;
+
+ uint64_t hash1 = parcHash64_Int32(data1);
+ uint64_t hash2 = parcHash64_Int32(data2);
+ uint64_t hash3 = parcHash64_Int32(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash64_Int64)
+{
+ uint64_t data1 = 10010010012345;
+ uint64_t data2 = 10010010012346;
+ uint64_t data3 = 10010010012345;
+
+ uint64_t hash1 = parcHash64_Int64(data1);
+ uint64_t hash2 = parcHash64_Int64(data2);
+ uint64_t hash3 = parcHash64_Int64(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Hash);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_HashCode.c b/libparc/parc/algol/test/test_parc_HashCode.c
new file mode 100755
index 00000000..a5b21137
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_HashCode.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_HashCode.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_HashCode)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_HashCode)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_HashCode)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCode_HashImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCode_HashHashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCode_Hash);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCode_HashImpl)
+{
+ PARCHashCode lastValue = 0;
+ uint8_t *memory = (uint8_t *) "1234";
+ size_t length = 4;
+
+ PARCHashCode expected = 3316911679945239212ULL;
+ PARCHashCode actual = parcHashCode_HashImpl(memory, length, lastValue);
+
+ assertTrue(expected == actual, "Expected %" PRIPARCHashCode " actual %" PRIPARCHashCode, expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCode_HashHashCode)
+{
+ PARCHashCode lastValue = 0;
+ uint8_t *memory = (uint8_t *) "1234";
+ size_t length = 4;
+
+ PARCHashCode lastHash = parcHashCode_HashImpl(memory, length, lastValue);
+
+ PARCHashCode hashedHash = parcHashCode_HashHashCode(lastHash, 123456);
+
+ assertTrue(lastHash != 0, "Expected a non zero hash value for lastHash");
+ assertTrue(hashedHash != 0, "Expected a non zero hash value for hashedHash");
+ assertTrue(lastHash != hashedHash, "Expected different hash values for hashedHash and lastHash");
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCode_Hash)
+{
+ char *testString1 = "this is some test data";
+ char *testString2 = "this is different test data";
+
+ PARCHashCode hash1 = parcHashCode_Hash((uint8_t *) testString1, strlen(testString1));
+ PARCHashCode hash2 = parcHashCode_Hash((uint8_t *) testString2, strlen(testString2));
+
+ assertTrue(hash1 != 0, "Expected a non zero hash value for testString1");
+ assertTrue(hash2 != 0, "Expected a non zero hash value for testString2");
+ assertTrue(hash1 != hash2, "Expected different hash values for testString1 and testString2");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_HashCode);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_HashCodeTable.c b/libparc/parc/algol/test/test_parc_HashCodeTable.c
new file mode 100755
index 00000000..c2adf9d2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_HashCodeTable.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include <config.h>
+
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#include <LongBow/unit-test.h>
+
+#include "../parc_HashCodeTable.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+
+// ==============================
+// The objects to put in the hash table. We have a separate key class and data class
+
+typedef struct test_key_class {
+ unsigned key_value;
+ unsigned hash_value;
+} TestKeyClass;
+
+typedef struct test_data_class {
+ unsigned data_value;
+} TestDataClass;
+
+static bool
+TestKeyClass_Equals(const void *a, const void *b)
+{
+ return ((TestKeyClass *) a)->key_value == ((TestKeyClass *) b)->key_value;
+}
+
+static HashCodeType
+TestKeyClass_Hash(const void *a)
+{
+ return ((TestKeyClass *) a)->hash_value;
+}
+
+static void
+TestKeyClassDestroy(void **aPtr)
+{
+ parcMemory_Deallocate((void **) aPtr);
+ aPtr = NULL;
+}
+
+static void
+TestDataClassDestroy(void **aPtr)
+{
+ parcMemory_Deallocate((void **) aPtr);
+ aPtr = NULL;
+}
+
+typedef struct truth_table_entry {
+ unsigned key_value;
+ unsigned hash_code;
+ unsigned data_value;
+} TruthTableEntry;
+
+// ==============================
+
+
+LONGBOW_TEST_RUNNER(parc_HashCodeTable)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_HashCodeTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_HashCodeTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_Get);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Create_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Del);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateHashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateValues);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_BigTable);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_Get)
+{
+ const int testsize = 4096;
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+ TruthTableEntry *truthtable = parcMemory_Allocate(sizeof(TruthTableEntry) * testsize);
+ assertNotNull(truthtable, "parcMemory_Allocate(%zu) returned NULL", sizeof(TruthTableEntry) * testsize);
+ int i;
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd == -1) {
+ assertFalse(fd == -1, "Error opening random number generator: %s", strerror(errno));
+ }
+
+ ssize_t nread = read(fd, truthtable, sizeof(TruthTableEntry) * testsize);
+ assertTrue(nread > 0, "Error using read");
+ close(fd);
+
+ for (i = 0; i < testsize; i++) {
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ key->key_value = truthtable[i].key_value;
+ key->hash_value = truthtable[i].hash_code;
+ data->data_value = truthtable[i].data_value;
+
+ bool success = parcHashCodeTable_Add(table, key, data);
+ assertTrue(success, "Failed inserting value");
+ }
+
+ // now retrieve them
+ for (i = 0; i < testsize; i++) {
+ TestKeyClass lookupkey;
+ lookupkey.key_value = truthtable[i].key_value;
+ lookupkey.hash_value = truthtable[i].hash_code;
+
+ TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey);
+ assertTrue(data->data_value == truthtable[i].data_value, "Data value incorrect");
+ }
+
+ parcHashCodeTable_Destroy(&table);
+ parcMemory_Deallocate((void **) &truthtable);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Create)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ assertNotNull(table, "table came back as null");
+ assertTrue(table->hashtable.tableSize == 0, "Hash table initialized to wrong size");
+ assertTrue(table->hashtable.tableLimit == MIN_SIZE, "Initial table limit size is wrong");
+ assertTrue(table->keyEqualsFunc == TestKeyClass_Equals, "KeyEqualsFunc wrong");
+ assertTrue(table->keyHashCodeFunc == TestKeyClass_Hash, "KeyHashFunc wrong");
+ assertTrue(table->keyDestroyer == TestKeyClassDestroy, "KeyDestroyer wrong");
+ assertTrue(table->dataDestroyer == TestDataClassDestroy, "DataDestroyer wrong");
+
+ parcHashCodeTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Create_Size)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create_Size(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy, 16);
+
+ assertNotNull(table, "table came back as null");
+ assertTrue(table->hashtable.tableLimit == 16, "Initial table limit size is wrong");
+ parcHashCodeTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Del)
+{
+ const int testsize = 6;
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+ TruthTableEntry *truthtable = parcMemory_Allocate(sizeof(TruthTableEntry) * testsize);
+ assertNotNull(truthtable, "parcMemory_Allocate(%zu) returned NULL", sizeof(TruthTableEntry) * testsize);
+ int i;
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd == -1) {
+ assertFalse(fd == -1, "Error opening random number generator: %s", strerror(errno));
+ }
+
+ ssize_t nread = read(fd, truthtable, sizeof(TruthTableEntry) * testsize);
+ assertTrue(nread > 0, "Error using read");
+ close(fd);
+
+ for (i = 0; i < testsize; i++) {
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ key->key_value = truthtable[i].key_value;
+ key->hash_value = truthtable[i].hash_code;
+ data->data_value = truthtable[i].data_value;
+
+ bool success = parcHashCodeTable_Add(table, key, data);
+ assertTrue(success, "Failed inserting value");
+ }
+
+ // delete the last one
+ {
+ TestKeyClass lookupkey;
+
+ lookupkey.key_value = truthtable[testsize - 1].key_value;
+ lookupkey.hash_value = truthtable[testsize - 1].hash_code;
+
+ parcHashCodeTable_Del(table, &lookupkey);
+ assertTrue(table->hashtable.tableSize == testsize - 1, "tableSize wrong");
+ }
+
+ for (i = 0; i < testsize - 1; i++) {
+ TestKeyClass lookupkey;
+ lookupkey.key_value = truthtable[i].key_value;
+ lookupkey.hash_value = truthtable[i].hash_code;
+
+ TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey);
+ assertTrue(data->data_value == truthtable[i].data_value, "Data value incorrect");
+ }
+
+ for (i = testsize - 1; i < testsize; i++) {
+ TestKeyClass lookupkey;
+ lookupkey.key_value = truthtable[i].key_value;
+ lookupkey.hash_value = truthtable[i].hash_code;
+
+ TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey);
+ assertNull(data, "Should not have returned deleted value");
+ }
+ parcHashCodeTable_Destroy(&table);
+ parcMemory_Deallocate((void **) &truthtable);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateHashes)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ TestKeyClass *key1 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestKeyClass *key2 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data1 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *data2 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *test;
+ bool success;
+
+ *key1 = (TestKeyClass) { .key_value = 1, .hash_value = 2 };
+ *key2 = (TestKeyClass) { .key_value = 3, .hash_value = 2 };
+ data1->data_value = 11;
+ data2->data_value = 22;
+
+ success = parcHashCodeTable_Add(table, key1, data1);
+ assertTrue(success, "Failed to add value");
+
+ success = parcHashCodeTable_Add(table, key2, data2);
+ assertTrue(success, "Failed to add value");
+
+ // value 3 should be in position 3
+ test = parcHashCodeTable_Get(table, key1);
+ assertNotNull(test, "returned null on get");
+ assertTrue(test->data_value == 11, "Got wrong value back for key1");
+
+ test = parcHashCodeTable_Get(table, key2);
+ assertNotNull(test, "returned null on get");
+ assertTrue(test->data_value == 22, "Got wrong value back for key1");
+
+ parcHashCodeTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateValues)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ TestKeyClass *key1 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestKeyClass *key2 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data1 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *data2 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *test;
+ bool success;
+
+ *key1 = (TestKeyClass) { .key_value = 1, .hash_value = 2 };
+ *key2 = (TestKeyClass) { .key_value = 1, .hash_value = 2 };
+ data1->data_value = 11;
+ data2->data_value = 22;
+
+ success = parcHashCodeTable_Add(table, key1, data1);
+ assertTrue(success, "Failed to add value");
+
+ success = parcHashCodeTable_Add(table, key2, data2);
+ assertFalse(success, "Second add should have failed on duplicate key");
+
+ // value 3 should be in position 3
+ test = parcHashCodeTable_Get(table, key1);
+ assertNotNull(test, "returned null on get");
+ assertTrue(test->data_value == 11, "Got wrong value back for key1");
+
+ parcHashCodeTable_Destroy(&table);
+ parcMemory_Deallocate((void **) &key2);
+ parcMemory_Deallocate((void **) &data2);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_BigTable)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ struct timeval t0, t1;
+
+ gettimeofday(&t0, NULL);
+
+ int loops = 1000;
+ for (int i = 0; i < loops; i++) {
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ *key = (TestKeyClass) { .key_value = i, .hash_value = i };
+ data->data_value = i;
+
+ bool success = parcHashCodeTable_Add(table, key, data);
+ assertTrue(success, "Failed to add value");
+ }
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+ double sec = t1.tv_sec + t1.tv_usec * 1E-6;
+ printf("expand count %u, sec = %.3f, sec/add = %.9f\n", table->expandCount, sec, sec / loops);
+
+ gettimeofday(&t0, NULL);
+ parcHashCodeTable_Destroy(&table);
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+ sec = t1.tv_sec + t1.tv_usec * 1E-6;
+ printf("destroy sec = %.3f, sec/add = %.9f\n", sec, sec / loops);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _findIndex);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _findIndex)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ // stick a data element in the middle of the table
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ key->key_value = 1;
+ key->hash_value = 37;
+ data->data_value = 7;
+
+ table->hashtable.entries[37].key = key;
+ table->hashtable.entries[37].hashcode = key->hash_value;
+ table->hashtable.entries[37].data = data;
+
+ size_t index;
+ bool success = _findIndex(table, key, &index);
+ assertTrue(success, "FindIndex did not find known value");
+ assertTrue(index == 37, "FindIndex returned wrong value");
+
+
+ parcHashCodeTable_Destroy(&table);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_HashCodeTable);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_HashMap.c b/libparc/parc/algol/test/test_parc_HashMap.c
new file mode 100644
index 00000000..1b071f44
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_HashMap.c
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_HashMap.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_HashMap)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(ObjectContract);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_HashMap)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_HashMap)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCapacity0);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCapacityNominal);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();");
+ parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance);
+
+ parcHashMap_Release(&instance);
+ assertNull(instance, "Expeced null result from parcHashMap_Release();");
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCapacity0)
+{
+ const size_t CAPACITY = 0;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(CAPACITY);
+ assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();");
+ parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCapacityNominal)
+{
+ const size_t CAPACITY = 10000;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(CAPACITY);
+ assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();");
+ parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance);
+ assertTrue(instance->capacity == CAPACITY, "Expect capacity to be %zu", CAPACITY);
+ assertTrue(instance->size == 0, "Expect size to be 0");
+
+ //Make sure all the buckets exist
+ for (size_t i = 0; i < CAPACITY; ++i) {
+ assertNull(instance->buckets[i], "Expect the hashmap to be clear");
+ }
+
+ parcHashMap_Release(&instance);
+ assertNull(instance, "Expeced null result from parcHashMap_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(ObjectContract)
+{
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Copy);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Display);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Equals);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_HashCode_Empty);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_HashCode_NonEmpty);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_IsValid);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_AssertValid);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_ToJSON);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ObjectContract)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ObjectContract)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Copy)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCHashMap *copy = parcHashMap_Copy(instance);
+
+ assertTrue(parcHashMap_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcHashMap_Release(&instance);
+ parcHashMap_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Display)
+{
+ PARCHashMap *x = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(x, key, value);
+ parcHashMap_Display(x, 0);
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&x);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Equals)
+{
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ PARCHashMap *x = parcHashMap_Create();
+ parcHashMap_Put(x, key, value);
+ PARCHashMap *y = parcHashMap_Create();
+ parcHashMap_Put(y, key, value);
+ PARCHashMap *z = parcHashMap_Create();
+ parcHashMap_Put(z, key, value);
+
+ PARCHashMap *u1 = parcHashMap_Create();
+
+ PARCHashMap *u2 = parcHashMap_Create();
+ parcHashMap_Put(u2, key, value);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcHashMap_Release(&x);
+ parcHashMap_Release(&y);
+ parcHashMap_Release(&z);
+ parcHashMap_Release(&u1);
+ parcHashMap_Release(&u2);
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_HashCode_Empty)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCHashCode code = parcHashMap_HashCode(instance);
+
+ assertTrue(code == 0, "Expected 0, actual %" PRIPARCHashCode, code);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_HashCode_NonEmpty)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ PARCHashCode code = parcHashMap_HashCode(instance);
+ assertTrue(code != 0, "Expected a non-zero hash code, actual %" PRIPARCHashCode, code);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_IsValid)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+ assertTrue(parcHashMap_IsValid(instance), "Expected parcHashMap_Create to result in a valid instance.");
+
+ parcHashMap_Release(&instance);
+ assertFalse(parcHashMap_IsValid(instance), "Expected parcHashMap_Create to result in an invalid instance.");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_AssertValid)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+ parcHashMap_AssertValid(instance);
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_ToJSON)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+
+ PARCJSON *json = parcHashMap_ToJSON(instance);
+
+ parcJSON_Release(&json);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_ToString)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+
+ char *string = parcHashMap_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcHashMap_ToString");
+
+ parcMemory_Deallocate(&string);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Put);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_PutN);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Put_Replace);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Get_NoValue);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Contains_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Contains_False);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Remove_False);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Resize);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_GetClusteringNumber);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator_HasNext);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator_Next);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_HasNext);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_Next);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_Remove);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Put)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ //size_t keyReferences = parcObject_GetReferenceCount(key);
+ size_t valueReferences = parcObject_GetReferenceCount(value);
+
+ parcHashMap_Put(instance, key, value);
+ //M.S. Put() now results in a copy of the key.
+ //assertTrue(keyReferences + 1 == parcObject_GetReferenceCount(key), "Expected key reference to be incremented by 1.");
+ assertTrue(valueReferences + 1 == parcObject_GetReferenceCount(value), "Expected value reference to be incremented by 1.");
+
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key);
+
+ assertTrue(parcBuffer_Equals(value, actual), "Expected value was not returned from Get");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+typedef struct {
+ int64_t number;
+} _Int;
+
+static char *
+_int_toString(const _Int *anInt)
+{
+ char *result = parcMemory_AllocateAndClear(22);
+ sprintf(result, "%" PRIi64 "", anInt->number);
+ return result;
+}
+
+static PARCHashCode
+_int_hashCode(const _Int *anInt)
+{
+ PARCHashCode result = anInt->number;
+
+ return result;
+}
+
+parcObject_ExtendPARCObject(_Int, NULL, NULL, _int_toString, NULL, NULL, _int_hashCode, NULL);
+
+parcObject_ImplementRelease(_int, _Int);
+
+static _Int *
+_int_Create(int64_t anInt)
+{
+ _Int *_int = parcObject_CreateInstance(_Int);
+
+ if (_int != NULL) {
+ _int->number = anInt;
+ }
+
+ return _int;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_GetClusteringNumber)
+{
+ size_t minimumSize = 100;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(minimumSize);
+
+ double maxLoadFactor = instance->maxLoadFactor;
+
+ // Load a hash map up to its load-factor
+ size_t testRunSize = minimumSize * maxLoadFactor - 20;
+ srand(time(NULL));
+ for (int i = 0; i < testRunSize; ++i) {
+ _Int *key = _int_Create(rand());
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ parcHashMap_Put(instance, key, value);
+ parcBuffer_Release(&value);
+ _int_Release(&key);
+ }
+
+ double currentClusteringNumber = parcHashMap_GetClusteringNumber(instance);
+
+ if (currentClusteringNumber < 0.5) {
+ testWarn("Oddly low clustering number detected.");
+ }
+
+ if (currentClusteringNumber > 1.5) {
+ testWarn("Oddly high clustering number detected.");
+ }
+
+ // This will load up one bucket
+ for (int i = 0; i < 20; ++i) {
+ _Int *key = _int_Create(1 + (100 * i));
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 10 + i);
+ parcHashMap_Put(instance, key, value);
+ parcBuffer_Release(&value);
+ _int_Release(&key);
+ }
+
+ currentClusteringNumber = parcHashMap_GetClusteringNumber(instance);
+
+ parcHashMap_Release(&instance);
+
+ if (currentClusteringNumber < 2.9) {
+ testWarn("Oddly low clustering number detected.");
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Resize)
+{
+ size_t initialSize = 8;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(initialSize);
+
+ PARCBuffer *key = parcBuffer_Allocate(sizeof(uint32_t));
+ PARCBuffer *value42 = parcBuffer_WrapCString("value42");
+ double maxLoadFactor = instance->maxLoadFactor;
+
+ // Load a hash map up to its load-factor
+ size_t testRunSize = initialSize * maxLoadFactor;
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value);
+ parcBuffer_Release(&value);
+ }
+ assertTrue(parcHashMap_Size(instance) == testRunSize, "Expect the size to be %zu", testRunSize);
+ assertTrue(instance->capacity == initialSize, "Expect to have the original capacity");
+
+ // Test for expected values
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+ }
+
+ // Add one more item to the the hash map, this should trigger an expansion
+ parcBuffer_PutUint32(key, 42);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value42);
+ assertTrue(parcHashMap_Size(instance) == testRunSize + 1, "Expect the size to be %zu", testRunSize);
+ assertTrue(instance->capacity == 2 * initialSize, "Expect to have the original capacity");
+
+ // Re-test value look ups to make sure the new hash map still maps correctly
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+ }
+ double averageBucketSize = parcHashMap_GetClusteringNumber(instance);
+ parcBuffer_PutUint32(key, 42);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value42, storedValue), "Expect to get back value42");
+ parcBuffer_Release(&value42);
+ assertTrue(parcHashMap_GetClusteringNumber(instance) <= averageBucketSize,
+ "Expect the average bucket size to be less then it was");
+
+ // Now test multiple expansions to make sure they happened are result in a valid hash map
+ size_t testCapacity = 1024;
+ // If we load up to (maxLoadFactor * testCapacity) + 1, the capacity should expand to 2 * testCapacity
+ testRunSize = (testCapacity * maxLoadFactor) + 1;
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value);
+ parcBuffer_Release(&value);
+ if (i == (testRunSize - 2)) {
+ averageBucketSize = parcHashMap_GetClusteringNumber(instance);
+ }
+ }
+ assertTrue(instance->capacity == (2 * testCapacity),
+ "Expect capacity to be %zu got %zu", (2 * testCapacity), instance->capacity);
+ assertTrue(parcHashMap_GetClusteringNumber(instance) < averageBucketSize,
+ "Expect the average bucket size to be less then it was");
+
+ // Now test multiple contractions.
+ // If we remove all elements from index "smallSize" (eg. 8) up we will be left with a map of size smallSize,
+ // the map capacity should be contracting and, because the minimum load factor is 0.25 and the contraction
+ // is a divide by 2, the last contraction should be from capacity of "smallSize * 4" (32) to one
+ // of "smallSize * 2" (16) when size goes from "smallSize +1" (9) to "smallSize" (8).
+ //
+ size_t smallSize = 8;
+ for (uint32_t i = smallSize; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ parcBuffer_Flip(key);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, key);
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+
+ assertTrue(parcHashMap_Remove(instance, key), "Expect Remove to succeed");
+ }
+ assertTrue(instance->size == smallSize,
+ "Expect the hash map to have size %zu, got %zu", smallSize, instance->size)
+ assertTrue(instance->capacity == (smallSize * 2),
+ "Expect capacity to be %zu, got %zu", (smallSize * 2), instance->capacity);
+
+ // Re-test value look ups to make sure the new hash map still maps correctly
+ for (uint32_t i = 0; i < smallSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+ }
+
+ parcBuffer_Release(&key);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_PutN)
+{
+ size_t testRunSize = 100;
+
+ PARCHashMap *instance = parcHashMap_CreateCapacity(testRunSize);
+
+ PARCBuffer *key = parcBuffer_Allocate(sizeof(uint32_t));
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ PARCBuffer *value42 = parcBuffer_WrapCString("value42");
+ for (uint32_t i = 0; i < testRunSize * 2; ++i) {
+ parcBuffer_PutUint32(key, i);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value);
+ if (i == 42) {
+ parcHashMap_Put(instance, key, value42);
+ }
+ }
+
+ parcBuffer_PutUint32(key, 42);
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value42, actual), "Expect to get back value42");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ parcBuffer_Release(&value42);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Put_Replace)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("value1");
+ PARCBuffer *value2 = parcBuffer_WrapCString("value2");
+
+ parcHashMap_Put(instance, key, value1);
+
+ parcHashMap_Put(instance, key, value2);
+
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key);
+
+ assertTrue(parcBuffer_Equals(value2, actual), "Expected value was not returned from Get");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&value2);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Get_NoValue)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key);
+
+ assertNull(actual, "Expected parcHashMap_Get to return NULL for non-existent key.");
+
+ parcBuffer_Release(&key);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Contains_True)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ bool actual = parcHashMap_Contains(instance, key);
+
+ assertTrue(actual, "Expected parcHashMap_Contains to return true");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Contains_False)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+
+ bool actual = parcHashMap_Contains(instance, key);
+
+ assertFalse(actual, "Expected parcHashMap_Contains to return NULL for non-existent key.");
+
+ parcBuffer_Release(&key);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Remove)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ bool actual = parcHashMap_Remove(instance, key);
+
+ assertTrue(actual, "Expected parcHashMap_Remove to return true.");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Remove_False)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ bool actual = parcHashMap_Remove(instance, key2);
+
+ assertFalse(actual, "Expected parcHashMap_Remove to return false.");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateValueIterator(instance);
+
+ assertNotNull(iterator, "Expected parcHashMap_ValueIterator to return non-null result");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator_HasNext)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateValueIterator(instance);
+
+ assertTrue(parcIterator_HasNext(iterator), "Expected parcIterator_HasNext to return true");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator_Next)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key1 = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value2 = parcBuffer_WrapCString("2");
+ PARCBuffer *key3 = parcBuffer_WrapCString("key3");
+ PARCBuffer *value3 = parcBuffer_WrapCString("3");
+ PARCBuffer *key4 = parcBuffer_WrapCString("key4");
+ PARCBuffer *value4 = parcBuffer_WrapCString("4");
+
+ parcHashMap_Put(instance, key1, value1);
+ parcHashMap_Put(instance, key2, value2);
+ parcHashMap_Put(instance, key3, value3);
+ parcHashMap_Put(instance, key4, value4);
+
+ PARCIterator *iterator = parcHashMap_CreateValueIterator(instance);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *actual = parcIterator_Next(iterator);
+ assertNotNull(actual, "Expected parcIterator_Next to return non-null");
+ assertTrue(parcBuffer_Remaining(actual) > 0, "The same value appeared more than once in the iteration");
+ parcBuffer_SetPosition(actual, parcBuffer_Limit(actual));
+ }
+ parcIterator_Release(&iterator);
+
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+ parcBuffer_Release(&key4);
+ parcBuffer_Release(&value4);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ assertNotNull(iterator, "Expected parcHashMap_KeyIterator to return non-null result");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_HasNext)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ assertTrue(parcIterator_HasNext(iterator), "Expected parcIterator_HasNext to return true");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_Next)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key1 = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value2 = parcBuffer_WrapCString("2");
+ PARCBuffer *key3 = parcBuffer_WrapCString("key3");
+ PARCBuffer *value3 = parcBuffer_WrapCString("3");
+ PARCBuffer *key4 = parcBuffer_WrapCString("key4");
+ PARCBuffer *value4 = parcBuffer_WrapCString("4");
+
+ parcHashMap_Put(instance, key1, value1);
+ parcHashMap_Put(instance, key2, value2);
+ parcHashMap_Put(instance, key3, value3);
+ parcHashMap_Put(instance, key4, value4);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *actual = parcIterator_Next(iterator);
+ assertNotNull(actual, "Expected parcIterator_Next to return non-null");
+ assertTrue(parcBuffer_Remaining(actual) > 0, "The same value appeared more than once in the iteration");
+ parcBuffer_SetPosition(actual, parcBuffer_Limit(actual));
+ }
+ parcIterator_Release(&iterator);
+
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+ parcBuffer_Release(&key4);
+ parcBuffer_Release(&value4);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_Remove)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key1 = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value2 = parcBuffer_WrapCString("2");
+ PARCBuffer *key3 = parcBuffer_WrapCString("key3");
+ PARCBuffer *value3 = parcBuffer_WrapCString("3");
+ PARCBuffer *key4 = parcBuffer_WrapCString("key4");
+ PARCBuffer *value4 = parcBuffer_WrapCString("4");
+
+ parcHashMap_Put(instance, key1, value1);
+ parcHashMap_Put(instance, key2, value2);
+ parcHashMap_Put(instance, key3, value3);
+ parcHashMap_Put(instance, key4, value4);
+
+ assertTrue(parcHashMap_Size(instance) == 4, "Expected 4, actual %zd", parcHashMap_Size(instance));
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *key = parcBuffer_Acquire(parcIterator_Next(iterator));
+ parcIterator_Remove(iterator);
+ assertNull(parcHashMap_Get(instance, key), "Expected deleted entry to not be gettable.");
+ parcBuffer_Release(&key);
+ }
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcHashMap_Size(instance) == 0, "Expected 0, actual %zd", parcHashMap_Size(instance));
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+ parcBuffer_Release(&key4);
+ parcBuffer_Release(&value4);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, parcHashMapEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, parcHashMapEntry)
+{
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ _PARCHashMapEntry *instance = _parcHashMapEntry_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ _parcHashMapEntry_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_HashMap);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_InputStream.c b/libparc/parc/algol/test/test_parc_InputStream.c
new file mode 100755
index 00000000..46d47862
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_InputStream.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_InputStream.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_InputStream)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_InputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_InputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream);
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Read);
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Release);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream_Read)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcInputStream_Finalize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, parcInputStream_Finalize)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_InputStream);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Iterator.c b/libparc/parc/algol/test/test_parc_Iterator.c
new file mode 100644
index 00000000..d5778721
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Iterator.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Iterator.c"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Iterator)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Iterator)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Iterator)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, parcIterator_CreateAcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s", longBowTestCase_GetName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static uint64_t _state;
+
+static void *
+init(PARCObject *object __attribute__((unused)))
+{
+ _state = 0;
+ return &_state;
+}
+
+static bool
+hasNext(PARCObject *object __attribute__((unused)), void *state)
+{
+ uint64_t *value = (uint64_t *) state;
+ return (*value < 5);
+}
+
+static void *
+next(PARCObject *object __attribute__((unused)), void *state)
+{
+ uint64_t *value = (uint64_t *) state;
+
+ (*value)++;
+ return state;
+}
+
+static void
+removex(PARCObject *object __attribute__((unused)), void **state)
+{
+}
+
+static void *
+getElement(PARCObject *object __attribute__((unused)), void *state)
+{
+ uint64_t *value = (uint64_t *) state;
+ return (void *) *value;
+}
+
+static void
+fini(PARCObject *object __attribute__((unused)), void *state __attribute__((unused)))
+{
+}
+
+static void
+assertValid(const void *state __attribute__((unused)))
+{
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, parcIterator_CreateAcquireRelease)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcIterator_Acquire, iterator);
+ parcBuffer_Release(&buffer);
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcIterator_HasNext);
+ LONGBOW_RUN_TEST_CASE(Global, parcIterator_Next);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcIterator_HasNext)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid);
+
+ while (parcIterator_HasNext(iterator)) {
+ uint64_t value = (uint64_t) parcIterator_Next(iterator);
+ printf("%" PRIu64 "\n", value);
+ }
+ parcBuffer_Release(&buffer);
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_CASE(Global, parcIterator_Next)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid);
+
+ while (parcIterator_HasNext(iterator)) {
+ uint64_t value = (uint64_t) parcIterator_Next(iterator);
+ printf("%" PRIu64 "\n", value);
+ }
+ parcBuffer_Release(&buffer);
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_CASE(Local, _finalize)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Iterator);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSON.c b/libparc/parc/algol/test/test_parc_JSON.c
new file mode 100644
index 00000000..d1825319
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSON.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_JSON.c"
+#include "../parc_JSONPair.c"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSON)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSON);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSON)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_JSON)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(JSON)
+{
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Equals);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_HashCode);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Copy);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Add);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetMembers);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetPairByName);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetValueByName);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetPairByIndex);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetValueByIndex);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_BuildString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ToString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ToCompactString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath_BadArrayIndex);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath_DeadEndPath);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ParseString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ParseBuffer_WithExcess);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Display);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddObject);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddInteger);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddBoolean);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddArray);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddValue);
+}
+
+typedef struct {
+ PARCJSON *json;
+ char *expected;
+ char *compactExpected;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(JSON)
+{
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ char *temp = "{ \"string\" : \"foo\\/bar\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"json\" : { \"string\" : \"foo\\/bar\" }, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }";
+ data->expected = parcMemory_StringDuplicate(temp, strlen(temp));
+
+ temp = "{\"string\":\"foo/bar\",\"null\":null,\"true\":true,\"false\":false,\"integer\":31415,\"float\":3.141500,\"json\":{\"string\":\"foo/bar\"},\"array\":[null,false,true,31415,\"string\",[null,false,true,31415,\"string\"],{}]}";
+ data->compactExpected = parcMemory_StringDuplicate(temp, strlen(temp));
+
+ data->json = parcJSON_ParseString(temp);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSON)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcJSON_Release(&data->json);
+ parcMemory_Deallocate(&data->expected);
+ parcMemory_Deallocate(&data->compactExpected);
+
+ parcMemory_Deallocate(&data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(JSON, parcJSON_CreateRelease)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ parcJSON_Release(&json);
+ assertNull(json, "Expected the NULL pointer side-effect of Release.");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSON *copy = parcJSON_Copy(data->json);
+
+ assertTrue(parcJSON_Equals(data->json, copy), "Expect copy to equal original");
+
+ parcJSON_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_HashCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCHashCode expected = parcHashCode_Hash((uint8_t *) data->compactExpected, strlen(data->compactExpected));
+
+ PARCHashCode hashCode = parcJSON_HashCode(data->json);
+
+ assertTrue(hashCode == expected, "Expect correct hash code");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Add)
+{
+ PARCJSON *json = parcJSON_Create();
+ {
+ PARCBuffer *string = parcBuffer_WrapCString("string");
+ PARCJSONValue *stringValue = parcJSONValue_CreateFromString(string);
+ PARCBuffer *stringName = parcBuffer_WrapCString("string");
+ PARCJSONPair *pair = parcJSONPair_Create(stringName, stringValue);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&stringName);
+ parcJSONValue_Release(&stringValue);
+ parcBuffer_Release(&string);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("null");
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("true");
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("false");
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(false);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("integer");
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("float");
+ PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.1415);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetMembers)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ char *s = parcJSON_ToString(data->json);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCList *members = parcJSON_GetMembers(data->json);
+ assertTrue(parcList_Size(members) == 8, "Expected 8, actual %zd", parcList_Size(members));
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetPairByName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int expected = 31415;
+ const PARCJSONPair *pair = parcJSON_GetPairByName(data->json, "integer");
+
+ PARCBuffer *name = parcJSONPair_GetName(pair);
+ PARCJSONValue *value = parcJSONPair_GetValue(pair);
+
+ int64_t actual = parcJSONValue_GetInteger(value);
+
+ PARCBuffer *expectedName = parcBuffer_WrapCString("integer");
+
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'integer', actual '%s'", (char *) parcBuffer_ToString(name));
+
+ assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual);
+
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetValueByName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int expected = 31415;
+ const PARCJSONValue *value = parcJSON_GetValueByName(data->json, "integer");
+
+ int64_t actual = parcJSONValue_GetInteger(value);
+
+ PARCBuffer *expectedName = parcBuffer_WrapCString("integer");
+
+ assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual);
+
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetPairByIndex)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSONPair *pair = parcJSON_GetPairByIndex(data->json, 0);
+ PARCBuffer *name = parcJSONPair_GetName(pair);
+ PARCBuffer *expectedName = parcBuffer_WrapCString("string");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'string', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 1);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("null");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'null', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 2);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("true");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'true', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 3);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("false");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'false', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 4);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("integer");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'integer', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 5);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("float");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'float', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 6);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("json");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'json', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 7);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("array");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'array', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetValueByIndex)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSONValue *value = parcJSON_GetValueByIndex(data->json, 0);
+ assertTrue(parcJSONValue_IsString(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 1);
+ assertTrue(parcJSONValue_IsNull(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 2);
+ assertTrue(parcJSONValue_IsBoolean(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 3);
+ assertTrue(parcJSONValue_IsBoolean(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 4);
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 5);
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 6);
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 7);
+ assertTrue(parcJSONValue_IsArray(value),
+ "Expected value to be type string");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_BuildString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSON_BuildString(data->json, composer, false);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ composer = parcBufferComposer_Create();
+ parcJSON_BuildString(data->json, composer, true);
+
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(data->compactExpected, actual) == 0, "Expected %s, actual %s", data->compactExpected, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ char *actual = parcJSON_ToString(data->json);
+ assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ToCompactString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ char *actual = parcJSON_ToCompactString(data->json);
+ assertTrue(strcmp(data->compactExpected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCJSON *json = data->json;
+
+ char *s = parcJSON_ToString(json);
+ printf("%s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ const PARCJSONValue *value = parcJSON_GetByPath(json, "/string");
+ assertTrue(parcJSONValue_IsString(value), "Expected /string to be a string type.");
+ value = parcJSON_GetByPath(json, "/null");
+ assertTrue(parcJSONValue_IsNull(value), "Expected /null to be a null type.");
+ value = parcJSON_GetByPath(json, "/true");
+ assertTrue(parcJSONValue_IsBoolean(value), "Expected /true to be a boolean type.");
+ value = parcJSON_GetByPath(json, "/integer");
+ assertTrue(parcJSONValue_IsNumber(value), "Expected /integer to be a number type.");
+ value = parcJSON_GetByPath(json, "/float");
+ assertTrue(parcJSONValue_IsNumber(value), "Expected /float to be a number type.");
+ value = parcJSON_GetByPath(json, "/array");
+ assertTrue(parcJSONValue_IsArray(value), "Expected /array to be an array type.");
+ value = parcJSON_GetByPath(json, "/nonexistent");
+ assertNull(value, "Expected /nonexistent to be NULL");
+
+ value = parcJSON_GetByPath(json, "/array/1");
+ assertTrue(parcJSONValue_IsBoolean(value), "Expected /array/0 to be a boolean type.");
+
+ value = parcJSON_GetByPath(json, "/array/5");
+ assertTrue(parcJSONValue_IsArray(value), "Expected /array/5 to be an array type.");
+
+ assertNotNull(value, "Expected non-null pair");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath_BadArrayIndex)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ const PARCJSONValue *value = parcJSON_GetByPath(data->json, "/array/100");
+ assertNull(value, "Expected null value return from parcJSON_GetByPath");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath_DeadEndPath)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ const PARCJSONValue *value = parcJSON_GetByPath(data->json, "/string/foo");
+ assertNull(value, "Expected null value return from parcJSON_GetByPath");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Equals)
+{
+ PARCJSON *x = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ PARCJSON *y = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ PARCJSON *z = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+
+ PARCJSON *notEqual1 = parcJSON_ParseString("{ \"string\" : \"string\" }");
+
+ PARCJSON *notEqual2 = parcJSON_ParseString("{ \"string\" : \"xyzzy\", \"integer\" : 1 }");
+
+ parcObjectTesting_AssertEqualsFunction(parcJSON_Equals, x, y, z, notEqual1, notEqual2);
+
+ parcJSON_Release(&x);
+ parcJSON_Release(&y);
+ parcJSON_Release(&z);
+ parcJSON_Release(&notEqual1);
+ parcJSON_Release(&notEqual2);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcJSON_Display(data->json, 0);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ParseString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSON *json = parcJSON_ParseString(data->expected);
+
+ char *actual = parcJSON_ToString(json);
+
+ assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ParseBuffer_WithExcess)
+{
+ char *string = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }Xhowdy";
+ PARCBuffer *buffer = parcBuffer_WrapCString((char *) string);
+
+ PARCJSON *json = parcJSON_ParseBuffer(buffer);
+
+ char actual = parcBuffer_GetUint8(buffer);
+ assertTrue(actual == 'X', "Expected buffer position to point to X, actual %x", actual);
+
+ parcBuffer_Release(&buffer);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddString)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "string";
+ char *expectedValue = "value";
+
+ parcJSON_AddString(json, expectedName, expectedValue);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, "string");
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s",
+ expectedName,
+ parcBuffer_ToString(actualName));
+ assertTrue(strcmp(expectedValue, parcBuffer_Overlay(parcJSONValue_GetString(actualValue), 0)) == 0,
+ "Expected value %s, actual %s",
+ expectedValue,
+ parcJSONValue_ToString(actualValue));
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddObject)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ PARCJSON *expectedValue = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ parcJSON_AddObject(json, "object", expectedValue);
+
+ char *expectedName = "object";
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+
+ assertTrue(parcJSON_Equals(expectedValue, parcJSONValue_GetJSON(actualValue)),
+ "Expected value did not match the actual value.");
+
+ parcJSON_Release(&expectedValue);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddInteger)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "integer";
+ uint64_t expectedValue = 12345;
+
+ parcJSON_AddInteger(json, expectedName, expectedValue);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+
+ assertTrue(expectedValue == parcJSONValue_GetInteger(actualValue),
+ "Expected %" PRIi64 "d actual %" PRIi64 "d", expectedValue, parcJSONValue_GetInteger(actualValue));
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddBoolean)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "boolean";
+ bool expectedValue = true;
+
+ parcJSON_AddBoolean(json, expectedName, expectedValue);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+
+ assertTrue(expectedValue == parcJSONValue_GetBoolean(actualValue),
+ "Expected %d actual %d", expectedValue, parcJSONValue_GetBoolean(actualValue));
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddArray)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "array";
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig");
+ parcJSONArray_AddValue(array, value);
+
+ parcJSON_AddArray(json, expectedName, array);
+ parcJSONArray_Release(&array);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+ assertTrue(parcJSONValue_IsArray(actualValue), "Expect value to be type PARCJSONArray");
+ array = parcJSONValue_GetArray(actualValue);
+ PARCJSONValue *result = parcJSONArray_GetValue(array, 0);
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(result), parcJSONValue_GetString(value)),
+ "Expected %s actual %s",
+ parcJSONValue_ToString(value),
+ parcJSONValue_ToString(result));
+
+ parcJSONValue_Release(&value);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddValue)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "value";
+
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig");
+
+ parcJSON_AddValue(json, expectedName, value);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+ assertTrue(parcJSONValue_IsString(actualValue), "Expect value to be type PARCJSONArray");
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(actualValue), parcJSONValue_GetString(value)),
+ "Expected %s actual %s",
+ parcJSONValue_ToString(value),
+ parcJSONValue_ToString(actualValue));
+
+ parcJSONValue_Release(&value);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSON);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONArray.c b/libparc/parc/algol/test/test_parc_JSONArray.c
new file mode 100755
index 00000000..d0ad9ec5
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONArray.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_JSONArray.c"
+
+#include <LongBow/unit-test.h>
+#include <stdio.h>
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONArray)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(parc_JSONArray);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONArray)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_JSONArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parc_JSONArray)
+{
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_Equals);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_AddValue);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_GetLength);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_GetValue);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_BuildString);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_ToString);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parc_JSONArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parc_JSONArray)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_CreateRelease)
+{
+ PARCJSONArray *expected = parcJSONArray_Create();
+ parcJSONArray_AssertValid(expected);
+ assertNotNull(expected, "Expected non-null return value from parcJSONArray_Create");
+
+ PARCJSONArray *actual = parcJSONArray_Acquire(expected);
+ parcJSONArray_AssertValid(actual);
+
+ parcJSONArray_Release(&actual);
+ assertNull(actual, "Expected null value set by parcJSONArray_Release");
+ parcJSONArray_AssertValid(expected);
+
+ parcJSONArray_Release(&expected);
+ assertNull(expected, "Expected null value set by parcJSONArray_Release");
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_Equals)
+{
+ PARCJSONArray *x = parcJSONArray_Create();
+ PARCJSONArray *y = parcJSONArray_Create();
+ PARCJSONArray *z = parcJSONArray_Create();
+
+ PARCJSONArray *notEqual1 = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Hello");
+ parcJSONArray_AddValue(notEqual1, value);
+ parcJSONValue_Release(&value);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONArray_Equals, x, y, z, notEqual1);
+
+ parcJSONArray_Release(&x);
+ parcJSONArray_Release(&y);
+ parcJSONArray_Release(&z);
+ parcJSONArray_Release(&notEqual1);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_AddValue)
+{
+ PARCJSONArray *expected = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(expected, value);
+ parcJSONValue_Release(&value);
+
+ parcJSONArray_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_GetLength)
+{
+ PARCJSONArray *expected = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(expected, value);
+ parcJSONValue_Release(&value);
+ assertTrue(parcJSONArray_GetLength(expected) == 1, "Expected a length of 1");
+
+ parcJSONArray_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_GetValue)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+
+ PARCJSONValue *actual = parcJSONArray_GetValue(array, 0);
+
+ assertTrue(expected == actual, "Expected different value");
+
+ parcJSONValue_Release(&expected);
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_BuildString)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONArray_BuildString(array, composer, false);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strlen(result) > 0, "Expected non-empty string result");
+
+ parcMemory_Deallocate((void **) &result);
+
+ composer = parcBufferComposer_Create();
+ parcJSONArray_BuildString(array, composer, true);
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strlen(result) > 0, "Expected non-empty string result");
+
+ parcMemory_Deallocate((void **) &result);
+
+ parcJSONValue_Release(&expected);
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_ToString)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+ parcJSONValue_Release(&expected);
+
+ const char *string = parcJSONArray_ToString(array);
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_Display)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+ parcJSONValue_Release(&expected);
+
+ parcJSONArray_Display(array, 0);
+
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONArray);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONPair.c b/libparc/parc/algol/test/test_parc_JSONPair.c
new file mode 100644
index 00000000..b8c0c3f9
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONPair.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_JSONPair.c"
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONPair)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSONPair);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONPair)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_JSONPair)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(JSONPair)
+{
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_BuildString);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_ToString);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Display);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Equals);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Parser);
+
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateNULL);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateValue);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateString);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromBoolean);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromInteger);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromFloat);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSONArray);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSON);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONPair)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONPair)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateAcquireRelease)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString("foo");
+ PARCJSONValue *value = parcJSONValue_CreateFromString(stringValue);
+ parcBuffer_Release(&stringValue);
+
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+
+ assertTrue(parcBuffer_Equals(name, pair->name),
+ "Expected '%s' actual '%s'", parcBuffer_ToString(name), parcBuffer_ToString(pair->name));
+ assertTrue(value == pair->value,
+ "Expected %p' actual %p", (void *) value, (void *) pair->value);
+
+ PARCJSONPair *reference = parcJSONPair_Acquire(pair);
+
+ assertTrue(reference == pair,
+ "Expected parcJSONPair_Acquire to return the same pointer as the original.");
+
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ parcJSONPair_Release(&reference);
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Display)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+ PARCBuffer *value = parcBuffer_WrapCString("foo");
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value);
+ parcBuffer_Release(&value);
+ PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&jsonValue);
+
+ parcJSONPair_Display(pair, 0);
+
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_BuildString)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+ PARCBuffer *value = parcBuffer_WrapCString("foo/bar");
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value);
+ parcBuffer_Release(&value);
+ PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&jsonValue);
+
+ // umcompressed
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONPair_BuildString(pair, composer, false);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ char *expected = "\"name\" : \"foo\\/bar\"";
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ // compressed
+ composer = parcBufferComposer_Create();
+ parcJSONPair_BuildString(pair, composer, true);
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ expected = "\"name\":\"foo/bar\"";
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_ToString)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+ PARCBuffer *value = parcBuffer_WrapCString("foo");
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value);
+ parcBuffer_Release(&value);
+ PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&jsonValue);
+
+ char *expected = "\"name\" : \"foo\"";
+ char *actual = parcJSONPair_ToString(pair);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateNULL)
+{
+ char *name = "MyNull";
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromNULL(name);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+
+ assertTrue(parcJSONValue_IsNull(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Null value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateValue)
+{
+ char *name = "MyNull";
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig");
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+
+ assertTrue(parcJSONValue_IsString(parcJSONPair_GetValue(pair)),
+ "Expected a String value.");
+
+ assertTrue(parcJSONPair_GetValue(pair) == value, "Expect values to be equal");
+
+ parcJSONValue_Release(&value);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateString)
+{
+ char *name = "MyNull";
+ char *value = "value";
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromCString(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromString(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected value '%s', Got '%s'", value, parcBuffer_ToString(parcJSONValue_GetString(parcJSONPair_GetValue(pair))));
+ assertTrue(parcJSONValue_IsString(parcJSONPair_GetValue(pair)),
+ "Expected a JSON String value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromBoolean)
+{
+ char *name = "MyNull";
+ bool value = true;
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromBoolean(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromBoolean(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected value '%d', Got '%d'", value, parcJSONValue_GetBoolean(parcJSONPair_GetValue(pair)));
+
+ assertTrue(parcJSONValue_IsBoolean(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Boolean value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromInteger)
+{
+ char *name = "MyNull";
+ int value = 31415;
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromInteger(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected value '%d', Got '%" PRIi64 "'", value, parcJSONValue_GetInteger(parcJSONPair_GetValue(pair)));
+
+ assertTrue(parcJSONValue_IsNumber(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Integer value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromFloat)
+{
+ char *name = "MyNull";
+ double value = 3.1;
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromFloat(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromDouble(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected %g, got %Lg", value, parcJSONValue_GetFloat(parcJSONPair_GetValue(pair)));
+
+ assertTrue(parcJSONValue_IsNumber(parcJSONPair_GetValue(pair)),
+ "Expected a JSON number value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSONArray)
+{
+ char *name = "MyNull";
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromJSONArray(array);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray(name, array);
+ parcJSONArray_Release(&array);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected the value to be equal the same array provided");
+
+ assertTrue(parcJSONValue_IsArray(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Array value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSON)
+{
+ char *name = "MyNull";
+ PARCJSON *value = parcJSON_Create();
+
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromJSON(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSON(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected %s", parcJSON_ToString(value));
+
+ assertTrue(parcJSONValue_IsJSON(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Object value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+ parcJSON_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Equals)
+{
+ char *name = "MyNull";
+ char *unequalName = "foo";
+ int value = 31415;
+ int unequalValue = 141;
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value);
+ PARCJSONPair *y = parcJSONPair_CreateFromInteger(name, value);
+ PARCJSONPair *z = parcJSONPair_CreateFromInteger(name, value);
+ PARCJSONPair *unequal1 = parcJSONPair_CreateFromInteger(name, unequalValue);
+ PARCJSONPair *unequal2 = parcJSONPair_CreateFromInteger(unequalName, unequalValue);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONPair_Equals, pair, y, z, unequal1, unequal2);
+
+ parcJSONPair_Release(&pair);
+ parcJSONPair_Release(&y);
+ parcJSONPair_Release(&z);
+ parcJSONPair_Release(&unequal1);
+ parcJSONPair_Release(&unequal2);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Parser)
+{
+ PARCBuffer *buffer = parcBuffer_AllocateCString("\"name\" : \"value\"");
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONPair *pair = parcJSONPair_Parser(parser);
+
+ assertTrue(parcBuffer_Position(parcJSONPair_GetName(pair)) == 0, "Expected the JSONPair name buffer to be 'reset'");
+
+ parcJSONPair_Release(&pair);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONPair);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONParser.c b/libparc/parc/algol/test/test_parc_JSONParser.c
new file mode 100755
index 00000000..63bcea8d
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONParser.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <math.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include "../parc_JSONParser.c"
+
+#include <parc/algol/parc_JSONValue.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+#include <parc/algol/parc_Memory.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONParser)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSONParse_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(JSONParse);
+// LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONParser)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_JSONParser)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_FIXTURE(JSONParse_CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_Create);
+ LONGBOW_RUN_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONParse_CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONParse_CreateAcquireRelease)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_Create)
+{
+ char *string = "\"string\"";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+ assertNull(parser,
+ "Expected parcJSONParser_Release to set the reference pointer to NULL");
+}
+
+LONGBOW_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_AcquireRelease)
+{
+ char *string = "\"string\"";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *expected = parcJSONParser_Create(buffer);
+
+ PARCJSONParser *actual = parcJSONParser_Acquire(expected);
+ assertTrue(actual == expected,
+ "Expected the acquired reference to be the same as the original instance.");
+
+ parcJSONParser_Release(&actual);
+ assertNull(actual,
+ "Expected parcJSONParser_Release to set the reference pointer to NULL");
+
+ parcJSONParser_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(JSONParse)
+{
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONString_Parser);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONParser_RequireString_Fail);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONString_Parser_Quoted);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_Parse);
+
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_ParseFile);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_ParseFileToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONParse)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONParse)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSONString_Parser)
+{
+ char *string = "\"\\\" \\\\ \\b \\f \\n \\r \\t \\/\"";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ PARCBuffer *expected = parcBuffer_AllocateCString("\" \\ \b \f \n \r \t /");
+ PARCBuffer *actual = parcJSONParser_ParseString(parser);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected string");
+
+ parcBuffer_Release(&actual);
+ parcBuffer_Release(&expected);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSONParser_RequireString_Fail)
+{
+ char *string = "\"string\"";
+ char *requiredString = "foo";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ bool actual = parcJSONParser_RequireString(parser, requiredString);
+
+ assertFalse(actual, "Expected parcJSONParser_RequireString to fail");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSONString_Parser_Quoted)
+{
+ char *string = "\"str\\\"ing\"";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ PARCBuffer *expected = parcBuffer_WrapCString("str\"ing");
+ PARCBuffer *actual = parcJSONParser_ParseString(parser);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected string");
+
+ parcBuffer_Release(&actual);
+ parcBuffer_Release(&expected);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSON_Parse)
+{
+ char *expected = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }";
+
+ expected = "{ \"integer\" : 31415 }";
+
+ expected = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { \"string\" : \"string\" } ] }";
+
+ PARCJSON *json = parcJSON_ParseString(expected);
+ assertNotNull(json, "Parse error for %s", expected);
+
+ char *actual = parcJSON_ToString(json);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ printf("%s\n", actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSON_ParseFile)
+{
+ char *string = NULL;
+ size_t nread = longBowDebug_ReadFile("data.json", &string);
+ assertTrue(nread != -1, "Cannot read '%s'", "data.json");
+
+ PARCJSON *json = parcJSON_ParseString(string);
+
+ assertNotNull(json, "parcJSON_ParseString failed");
+
+ // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0,
+ // "Can't write file");
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSON_ParseFileToString)
+{
+ char *string = NULL;
+ size_t nread = longBowDebug_ReadFile("data.json", &string);
+ assertTrue(nread != -1, "Cannot read '%s'", "data.json");
+
+ PARCJSON *json = parcJSON_ParseString(string);
+
+ assertNotNull(json, "parcJSON_ParseString failed");
+
+ char *actual = parcJSON_ToString(json);
+
+ // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0,
+ // "Can't write file");
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Performance)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcJSON_ParseFileToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcJSON_ParseFileToString)
+{
+ char *string = NULL;
+ size_t nread = longBowDebug_ReadFile("citylots.json", &string);
+ assertTrue(nread != -1, "Cannot read '%s'", "citylots.json");
+
+ PARCJSON *json = parcJSON_ParseString(string);
+
+ assertNotNull(json, "parcJSON_ParseString failed");
+
+ char *actual = parcJSON_ToString(json);
+
+ // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0,
+ // "Can't write file");
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONParser);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONValue.c b/libparc/parc/algol/test/test_parc_JSONValue.c
new file mode 100644
index 00000000..804eb690
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONValue.c
@@ -0,0 +1,1365 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include "../parc_JSONValue.c"
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONValue)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSONValue_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(JSONValue);
+ LONGBOW_RUN_TEST_FIXTURE(JSONValueParsing);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONValue)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_JSONValue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(JSONValue_CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(JSONValue_CreateAcquireRelease, _createValue);
+ LONGBOW_RUN_TEST_CASE(JSONValue_CreateAcquireRelease, parcJSONValue_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONValue_CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValue_CreateAcquireRelease)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONValue_CreateAcquireRelease, _createValue)
+{
+ PARCJSONValue *result = parcJSONValue_CreateFromNULL();
+
+ assertNotNull(result, "Expected non-null return value from _createValue");
+ assertTrue(parcJSONValue_IsNull(result),
+ "Expected PARCJSONValueType_Null");
+
+ parcJSONValue_Release(&result);
+ assertNull(result, "Expected parcJSONValue_Release to NULL the instance pointer.");
+}
+
+
+LONGBOW_TEST_CASE(JSONValue_CreateAcquireRelease, parcJSONValue_AcquireRelease)
+{
+ PARCJSONValue *result = parcJSONValue_CreateFromNULL();
+
+ assertNotNull(result, "Expected non-null return value from _createValue");
+ assertTrue(parcJSONValue_IsNull(result),
+ "Expected PARCJSONValueType_Null");
+
+ PARCJSONValue *actual = parcJSONValue_Acquire(result);
+ assertTrue(result == actual, "Expected parcJSONValue_Acquire return value to be same as the original.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONValue_Release(&result);
+ assertNull(result, "Expected parcJSONValue_Release to NULL the instance pointer.");
+}
+
+
+LONGBOW_TEST_FIXTURE(JSONValue)
+{
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_NULL);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Boolean);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Float);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Integer);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_String);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_JSON);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Array);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Timespec);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Timeval);
+
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Display);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_BuildString);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_NULL);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Array);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Boolean);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Float);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Integer);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_String);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_CreateCString);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_JSON);
+
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_NULL);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Boolean);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Integer);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Float);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_String);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Object);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Array);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONValue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValue)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_IsValid)
+{
+ bool actual = parcJSONValue_IsValid(NULL);
+ assertFalse(actual, "Expected a NULL value to be invalid");
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+
+ actual = parcJSONValue_IsValid(value);
+ parcJSONValue_Release(&value);
+ assertTrue(actual, "Expected a NULL value to be invalid");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_JSON)
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected PARCJSONValueType_JSON");
+
+ assertTrue(parcJSONValue_GetJSON(value) == json,
+ "Expected parcJSONValue_GetJSON to return the original instance pointer.");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Timeval)
+{
+ struct timeval timeval = { .tv_sec = 42, .tv_usec = 23 };
+ PARCJSONValue *value = parcJSONValue_CreateFromTimeval(&timeval);
+
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected PARCJSONValueType_JSON");
+
+ struct timeval actual;
+ parcJSONValue_GetTimeval(value, &actual);
+ assertTrue(timeval.tv_sec == actual.tv_sec, "Expected seconds to be equal.");
+ assertTrue(timeval.tv_usec == actual.tv_usec, "Expected seconds to be equal.");
+
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Timespec)
+{
+ struct timespec timespec = { .tv_sec = 42, .tv_nsec = 23 };
+ PARCJSONValue *value = parcJSONValue_CreateFromTimespec(&timespec);
+
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected PARCJSONValueType_JSON");
+
+ struct timespec testTS;
+ parcJSONValue_GetTimespec(value, &testTS);
+ assertTrue(memcmp(&timespec, &testTS, sizeof(struct timespec)) == 0,
+ "Expected parcJSONValue_GetTimespec to return the original instance pointer.");
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_NULL)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+
+ assertTrue(value->type == PARCJSONValueType_Null,
+ "Expected PARCJSONValueType_Null, actual %d", value->type);
+ assertTrue(parcJSONValue_IsNull(value),
+ "Expected PARCJSONValueType_Null");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Boolean)
+{
+ bool expected = true;
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(expected);
+
+ assertTrue(value->type == PARCJSONValueType_Boolean,
+ "Expected PARCJSONValueType_BooleanON_VALUE_BOOLEAN, actual %d", value->type);
+ assertTrue(value->value.boolean == expected, "Expected %d actual %d", expected, value->value.boolean);
+
+ assertTrue(parcJSONValue_IsBoolean(value),
+ "Expected PARCJSONValueType_Boolean");
+ assertTrue(parcJSONValue_GetBoolean(value), "Expected value to be true");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Float)
+{
+ double expected = 3.1415;
+ PARCJSONValue *value = parcJSONValue_CreateFromFloat(expected);
+
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected parcJSONValue_IsNumber to be true.");
+ assertTrue(parcJSONValue_GetFloat(value) == expected,
+ "Expected %g, actual %Lg", expected, parcJSONValue_GetFloat(value));
+
+ char *expectedString = "3.141500";
+ char *actualString = parcJSONValue_ToString(value);
+ assertTrue(strcmp(expectedString, actualString) == 0, "Exepcted %s, actual %s", expectedString, actualString);
+ parcMemory_Deallocate((void **) &actualString);
+
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Integer)
+{
+ int expected = 31415;
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(expected);
+
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected parcJSONValue_IsNumber");
+ int64_t actual = parcJSONValue_GetInteger(value);
+ assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual);
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_String)
+{
+ PARCBuffer *expected = parcBuffer_WrapCString("31415");
+ PARCJSONValue *value = parcJSONValue_CreateFromString(expected);
+
+ assertTrue(value->type == PARCJSONValueType_String,
+ "Expected parcJSONValueType.String, actual %d", value->type);
+ assertTrue(parcBuffer_Equals(value->value.string, expected),
+ "Expected %s actual %s", parcBuffer_ToString(expected), parcBuffer_ToString(value->value.string));
+ assertTrue(parcJSONValue_IsString(value),
+ "Expected PARCJSONValueType_String");
+
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(value), expected), "Expected value did not match actual value");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+ parcBuffer_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_CreateCString)
+{
+ PARCBuffer *expected = parcBuffer_WrapCString("31415");
+
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("31415");
+
+ assertTrue(value->type == PARCJSONValueType_String,
+ "Expected parcJSONValueType.String, actual %d", value->type);
+
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(value), expected), "Assert:")
+ {
+ char *expectedString = parcBuffer_ToString(expected);
+ char *actualString = parcBuffer_ToString(parcJSONValue_GetString(value));
+ printf("Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) &expectedString);
+ parcMemory_Deallocate((void **) &actualString);
+ }
+
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+ parcBuffer_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Array)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromJSONArray(array);
+
+ parcJSONValue_Release(&value);
+
+ parcJSONArray_Release(&array);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_BuildString)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(false);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(true);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromInteger(31415);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString("stringA/stringB");
+ value = parcJSONValue_CreateFromString(stringValue);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ parcBuffer_Release(&stringValue);
+
+ value = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+
+ // Uncompacted
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONValue_BuildString(value, composer, false);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ char *expected = "[ null, false, true, 31415, \"stringA\\/stringB\" ]";
+
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ // Compacted
+ composer = parcBufferComposer_Create();
+ parcJSONValue_BuildString(value, composer, true);
+
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ expected = "[null,false,true,31415,\"stringA/stringB\"]";
+
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Array)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(false);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(true);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromInteger(31415);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString("stringA/stringB");
+ value = parcJSONValue_CreateFromString(stringValue);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ parcBuffer_Release(&stringValue);
+
+ value = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+
+ char *expected = "[ null, false, true, 31415, \"stringA\\/stringB\" ]";
+ char *actual = parcJSONValue_ToString(value);
+
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Display)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(true);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromCString("hello");
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromFloat(3.14);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromInteger(314);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ value = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+ parcJSONArray_Release(&array);
+
+ PARCJSON *json = parcJSON_Create();
+ value = parcJSONValue_CreateFromJSON(json);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_NULL)
+{
+ char *expected = "null";
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Boolean)
+{
+ char *expected = "true";
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(expected);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Float)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ long double error;
+ } successful[] = {
+ { "-0.0415e-12", -0.0415e-12, 0.00001e-12 },
+ { "-0.0415e12", -0.0415e12, 0.00001e12 },
+ { "-0.0415", -0.0415, 0.00001 },
+ { "-3.0415", -3.0415, 0.00001 },
+ { "123.456", 123.456, 0.0001 },
+ { "123.456e78", 123.456e78, 0.0001e78 },
+ { "123.456e-78", 123.456e-78, 0.0001e-78 },
+ { "123.456e-78", 123.456e-78, 0.0001e-78 },
+ { "4e1", 40.0, 0.0001e-78 },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *expected = _parcJSONValue_NumberParser(parser);
+
+ char *string = parcJSONValue_ToString(expected);
+ assertTrue(strcmp(successful[i].string, string) == 0,
+ "Expected %s, actual %s", successful[i].string, string);
+ parcMemory_Deallocate((void **) &string);
+
+ parcJSONValue_Release(&expected);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Integer)
+{
+ char *expected = "31415";
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_String)
+{
+ char *input = "31415\b";
+ char *expected = "\"31415\\b\"";
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString(input);
+ PARCJSONValue *value = parcJSONValue_CreateFromString(stringValue);
+ parcBuffer_Release(&stringValue);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_JSON)
+{
+ char *expected = "{ }";
+ PARCJSON *json = parcJSON_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_NULL)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromNULL();
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromNULL();
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromNULL();
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Boolean)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromBoolean(true);
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromBoolean(true);
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromBoolean(true);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromBoolean(false);
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Integer)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromInteger(31415);
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromInteger(31415);
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromInteger(31415);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromInteger(4);
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Float)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromFloat(3.1415);
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromFloat(3.1415);
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromFloat(3.1415);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_String)
+{
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *example = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ stringBuffer = parcBuffer_AllocateCString("World");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Object)
+{
+ char *string = "{ \"name\" : 1, \"name2\" : 2 }";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *x = parcJSONValue_ObjectParser(parser);
+ parcJSONParser_Release(&parser);
+
+ assertTrue(parcJSONValue_IsJSON(x), "Expected a JSON Object value.");
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *y = parcJSONValue_ObjectParser(parser);
+ parcJSONParser_Release(&parser);
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *z = parcJSONValue_ObjectParser(parser);
+ parcJSONParser_Release(&parser);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ PARCJSON *json = parcJSON_Create();
+ PARCJSONValue *unequal2 = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, x, y, z, unequal1, unequal2);
+
+ parcJSONValue_Release(&x);
+ parcJSONValue_Release(&y);
+ parcJSONValue_Release(&z);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&unequal2);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Array)
+{
+ char *string = "[ \"name\", 1, true, false, null, [ ], { } ]";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *x = _parcJSONValue_ArrayParser(parser);
+ parcJSONParser_Release(&parser);
+
+ assertTrue(parcJSONValue_IsArray(x), "Expected a JSON Array value.");
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *y = _parcJSONValue_ArrayParser(parser);
+ parcJSONParser_Release(&parser);
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *z = _parcJSONValue_ArrayParser(parser);
+ parcJSONParser_Release(&parser);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *unequal2 = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, x, y, z, unequal1, unequal2);
+
+ parcJSONValue_Release(&x);
+ parcJSONValue_Release(&y);
+ parcJSONValue_Release(&z);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&unequal2);
+}
+
+LONGBOW_TEST_FIXTURE(JSONValueParsing)
+{
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser_Bad);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser_Bad);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser_Bad);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair2);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ArrayParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser_BAD);
+
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_NumberParser_BatchedFloat);
+
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Comma);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_CloseBracket);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Null);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_True);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_False);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_String);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Array);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Object);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONValueParsing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValueParsing)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser)
+{
+ char *string = "null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_NullParser(parser);
+
+ assertTrue(parcJSONValue_IsNull(actual), "Expected a JSON Null value.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser_Bad)
+{
+ char *string = "nulx";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_NullParser(parser);
+
+ assertNull(actual, "Expected a NULL return value");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser)
+{
+ char *string = "true";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_TrueParser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual), "Expected a JSON Boolean value.");
+ assertTrue(parcJSONValue_GetBoolean(actual), "Expected true.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser_Bad)
+{
+ char *string = "trux";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_TrueParser(parser);
+
+ assertNull(actual, "Expected a NULL return value");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser)
+{
+ char *string = "false";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_FalseParser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual), "Expected a JSON Boolean value.");
+ assertFalse(parcJSONValue_GetBoolean(actual), "Expected false.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser_Bad)
+{
+ char *string = "falsx";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_FalseParser(parser);
+
+ assertNull(actual, "Expected a NULL return value");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser)
+{
+ char *parserInput = "\"\\\" \\\\ \\b \\f \\n \\r \\t \\/\"";
+ PARCBuffer *buffer = parcBuffer_WrapCString(parserInput);
+ PARCBuffer *expected = parcBuffer_AllocateCString("\" \\ \b \f \n \r \t /");
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_StringParser(parser);
+
+ assertTrue(parcJSONValue_IsString(actual),
+ "Expected a JSON String value.");
+
+ assertTrue(parcBuffer_Equals(expected, actual->value.string),
+ "Expected '%s' actual '%s'", parcBuffer_ToString(expected), parcBuffer_ToString(actual->value.string))
+ {
+ parcBuffer_Display(expected, 0);
+ parcBuffer_Display(actual->value.string, 0);
+ }
+
+ char *string = parcJSONValue_ToString(actual);
+ assertTrue(strcmp(parserInput, string) == 0,
+ "Expected %s, actual %s", parserInput, string);
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser_BAD)
+{
+ char *bad[] = {
+ "\"\t\"",
+ "\"",
+ NULL
+ };
+
+ for (int i = 0; bad[i] != NULL; i++) {
+ char *parserInput = bad[i];
+ PARCBuffer *buffer = parcBuffer_WrapCString(parserInput);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_StringParser(parser);
+
+ assertNull(actual, "Expected failure");
+ parcBuffer_Release(&buffer);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser)
+{
+ char *string = "{ \"name\" : 1, \"name2\" : 2 }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_ObjectParser(parser);
+
+ assertTrue(parcJSONValue_IsJSON(actual), "Expected a JSON Object value.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair)
+{
+ char *string = "{ \"name\" , \"name2\" : 2 }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_ObjectParser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_ObjectParser to return NULL indicating failure");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair2)
+{
+ char *string = "{ 2 }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_ObjectParser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_ObjectParser to return NULL indicating failure");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ArrayParser)
+{
+ char *string = "[ \"name\", 1, true, false, null, [ ], { } ]";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_ArrayParser(parser);
+
+ assertTrue(parcJSONValue_IsArray(actual), "Expected a JSON Array value.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_NumberParser_BatchedFloat)
+{
+ struct test_values {
+ char *string;
+ char *expectedString;
+ long double floatValue;
+ int64_t integerValue;
+ long double floatTolerance;
+ } successful[] = {
+ { "0", "0", 0.0, 0, 0 },
+ { " 1", "1", 1.0, 1, 0 },
+ { "-1", "-1", -1.0, -1, 0 },
+ { "1e1", "1e1", 1.0e1, 10, 0 },
+ { "-2e1", "-2e1", -2.0e1, -2e1, 0 },
+ { "-2e+1", "-2e1", -2.0e+1, -2e+1, 0 },
+ { " 1.0", "1", 1.0, 1, 0 },
+ { "3e-1", "3e-1", 3e-1, 0, 0.01e-1 },
+ { "100e-2", "100e-2", 100e-2, 100e-2, 0.0001 },
+ { "123.456e11", "123.456e11", 123.456e11, 12345600000000, 0.0001e11 },
+ { "-0.0415e-12", "-0.0415e-12", -0.0415e-12, 0, 0.00001e-12 },
+ { "-0.0415e12", "-0.0415e12", -0.0415e12, -41500000000, 0.00001e12 },
+ { "-0.0415", "-0.0415", -0.0415, 0, 0.00001 },
+ { "-3.0415", "-3.0415", -3.0415, -3, 0.00001 },
+ { "123.456", "123.456", 123.456, 123, 0.0001 },
+ { "123.456e+11", "123.456e11", 123.456e+11, 12345600000000, 0.0001e+11 },
+ { "123.456e-11", "123.456e-11", 123.456e-11, 0, 0.0001e-11 },
+ { "1e-1", "1e-1", 1e-1, 0, 0.1e-1 },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *expected = _parcJSONValue_NumberParser(parser);
+ assertNotNull(expected, "_parcJSONValue_NumberParser returned NULL");
+
+ long double floatValue = parcJSONValue_GetFloat(expected);
+
+ assertTrue(fabsl(floatValue - successful[i].floatValue) <= successful[i].floatTolerance,
+ "Expected %Lf actual %Lf", successful[i].floatValue, floatValue);
+
+ char *string = parcJSONValue_ToString(expected);
+ assertTrue(strcmp(successful[i].expectedString, string) == 0,
+ "Expected %s actual %s", successful[i].expectedString, string);
+ parcMemory_Deallocate((void **) &string);
+
+ int64_t integerValue = parcJSONValue_GetInteger(expected);
+ assertTrue(integerValue == (int64_t) successful[i].integerValue,
+ "Expected %" PRIi64 " actual %" PRIi64 "", (int64_t) successful[i].integerValue, integerValue);
+
+ parcJSONValue_Release(&expected);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Comma)
+{
+ char *string = ", null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_Parser to return NULL when encountering a comma");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_CloseBracket)
+{
+ char *string = "], null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_Parser to return NULL when encountering a ]");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Null)
+{
+ char *string = " null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsNull(actual),
+ "Expected parcJSONValue_Parser to return a Null JSON value when encountering 'null'");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_True)
+{
+ char *string = " true";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual),
+ "Expected parcJSONValue_Parser to return a boolean JSON value when encountering 'true'");
+ assertTrue(parcJSONValue_GetBoolean(actual),
+ "Expected true");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_False)
+{
+ char *string = " false";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual),
+ "Expected parcJSONValue_Parser to return a boolean JSON value when encountering 'false'");
+ assertFalse(parcJSONValue_GetBoolean(actual),
+ "Expected true");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_String)
+{
+ char *string = " \"string\"";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsString(actual),
+ "Expected parcJSONValue_Parser to return a string JSON value");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Array)
+{
+ char *string = " [ ]";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *value = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsArray(value),
+ "Expected parcJSONValue_Parser to return a array JSON value");
+
+ PARCJSONArray *array = parcJSONValue_GetArray(value);
+ assertNotNull(array, "Expected a non-null pointer to a PARCJSONArray");
+
+ parcJSONValue_Release(&value);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Object)
+{
+ char *string = " { }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsJSON(actual),
+ "Expected parcJSONValue_Parser to return a JSON object value");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _parseSign_Negative);
+ LONGBOW_RUN_TEST_CASE(Static, _parseSign_NotASign);
+ LONGBOW_RUN_TEST_CASE(Static, _parseSign_Nil);
+
+ LONGBOW_RUN_TEST_CASE(Static, _parseWholeNumber);
+ LONGBOW_RUN_TEST_CASE(Static, _parseOptionalFraction);
+ LONGBOW_RUN_TEST_CASE(Static, _parseOptionalExponent);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _parseSign_Negative)
+{
+ char *string = "-";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+ int sign;
+ bool result = _parseSign(parser, &sign);
+
+ assertTrue(result, "Expected true from _parseSign()");
+
+ parcJSONParser_Release(&parser);
+}
+
+LONGBOW_TEST_CASE(Static, _parseSign_NotASign)
+{
+ char *string = "asd";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+ int sign;
+ bool result = _parseSign(parser, &sign);
+
+ assertFalse(result, "Expected true from _parseSign()");
+
+ parcJSONParser_Release(&parser);
+}
+
+LONGBOW_TEST_CASE(Static, _parseSign_Nil)
+{
+ char *string = "";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+ int sign;
+ bool result = _parseSign(parser, &sign);
+
+ assertTrue(result, "Expected true from _parseSign()");
+
+ parcJSONParser_Release(&parser);
+}
+
+LONGBOW_TEST_CASE(Static, _parseWholeNumber)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ } successful[] = {
+ { "0", 0 },
+ { "1", 1 },
+ { "123", 123 },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int64_t value = 0;
+
+ bool actual = _parseWholeNumber(parser, &value);
+
+ assertTrue(actual, "Expected true from _parseNumber()");
+ assertTrue(value == successful[i].value,
+ "Expected %Lf actual %" PRIi64 "", successful[i].value, value);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(Static, _parseOptionalFraction)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ bool correct;
+ } successful[] = {
+ { ".0", 0, true },
+ { ".", 0, false },
+ { ".1", 1, true },
+ { "crap", 0, false },
+ { "}", 0, true },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int64_t value = 0;
+ int log10OfFraction;
+
+ bool actual = _parseOptionalFraction(parser, &value, &log10OfFraction);
+
+ assertTrue(actual == successful[i].correct, "Expected true from _parseNumber()");
+ assertTrue(value == successful[i].value,
+ "Expected %Lf actual %" PRIi64 "", successful[i].value, value);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(Static, _parseOptionalExponent)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ bool correct;
+ } successful[] = {
+ { "e", 0, false },
+ { "ex", 0, false },
+ { "e-1", -1, true },
+ { "e1", 1, true },
+ { "e+1", 1, true },
+ { "x", 0, false },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int64_t value = 0;
+
+ bool actual = _parseOptionalExponent(parser, &value);
+
+ assertTrue(actual == successful[i].correct, "Expected true from _parseNumber()");
+ assertTrue(value == successful[i].value,
+ "Expected %Lf actual %" PRIi64 "", successful[i].value, value);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONValue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_KeyValue.c b/libparc/parc/algol/test/test_parc_KeyValue.c
new file mode 100755
index 00000000..f9440602
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_KeyValue.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *
+ */
+#include <config.h>
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_KeyValue.c"
+
+
+LONGBOW_TEST_RUNNER(parc_KeyValue)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(PARCKeyValueAsPARCObject);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_KeyValue)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_KeyValue)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(PARCKeyValueAsPARCObject)
+{
+ LONGBOW_RUN_TEST_CASE(PARCKeyValueAsPARCObject, parcObject_Conformance);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(PARCKeyValueAsPARCObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(PARCKeyValueAsPARCObject)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(PARCKeyValueAsPARCObject, parcObject_Conformance)
+{
+ PARCBuffer *key = parcBuffer_WrapCString("Key_1");
+ PARCBuffer *value = parcBuffer_WrapCString("Value");
+ PARCKeyValue *inst1 = parcKeyValue_Create(key, value);
+ PARCKeyValue *inst2 = parcKeyValue_Create(key, value);
+ PARCKeyValue *inst3 = parcKeyValue_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ key = parcBuffer_WrapCString("Key_0");
+ value = parcBuffer_WrapCString("Value");
+ PARCKeyValue *lesser = parcKeyValue_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ key = parcBuffer_WrapCString("Key_2");
+ value = parcBuffer_WrapCString("Value");
+ PARCKeyValue *greater = parcKeyValue_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, lesser, greater);
+
+ parcKeyValue_Release(&inst1);
+ parcKeyValue_Release(&inst2);
+ parcKeyValue_Release(&inst3);
+ parcKeyValue_Release(&lesser);
+ parcKeyValue_Release(&greater);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_GetValue);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_EqualKeys);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_SetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_SetValue);
+}
+
+typedef struct {
+ PARCKeyValue *testKV1;
+ PARCKeyValue *testKV2;
+ PARCKeyValue *nullValue;
+ PARCBuffer *key1;
+ PARCBuffer *value1;
+ PARCBuffer *key2;
+ PARCBuffer *value2;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->key1 = parcBuffer_WrapCString("This is key 1");
+ data->value1 = parcBuffer_WrapCString("This is value 1");
+ data->key2 = parcBuffer_WrapCString("This is key 2");
+ data->value2 = parcBuffer_WrapCString("This is value 2");
+
+ data->testKV1 = parcKeyValue_Create(data->key1, data->value1);
+ data->testKV2 = parcKeyValue_Create(data->key2, data->value2);
+
+ PARCBuffer *nullKey = parcBuffer_WrapCString("NULL KEY");
+ data->nullValue = parcKeyValue_Create(nullKey, NULL);
+ parcBuffer_Release(&nullKey);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcBuffer_Release(&data->key1);
+ parcBuffer_Release(&data->value1);
+ parcBuffer_Release(&data->key2);
+ parcBuffer_Release(&data->value2);
+
+ parcKeyValue_Release(&data->testKV1);
+ parcKeyValue_Release(&data->testKV2);
+ parcKeyValue_Release(&data->nullValue);
+
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->testKV1, "Expect a non-NULL key value");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->testKV1, "Expect a non-NULL key value");
+
+ PARCKeyValue *kv = parcKeyValue_Acquire(data->testKV1);
+ parcKeyValue_Release(&kv);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_GetKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetKey(data->testKV1), data->key1),
+ "The key returned is not the key provided");
+
+ assertNotNull(parcKeyValue_GetKey(data->nullValue), "Expect Non-NULL key from NULL value kv");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_GetValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1), data->value1),
+ "The key returned is not the key provided");
+
+ assertNull(parcKeyValue_GetValue(data->nullValue), "Expect NULL from GetValue");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool isEqual = parcKeyValue_Equals(data->testKV1, data->testKV2);
+ assertFalse(isEqual, "Expect test key-values to not be equal");
+
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2);
+ isEqual = parcKeyValue_Equals(kv, data->testKV1) || parcKeyValue_Equals(kv, data->testKV2);
+ parcKeyValue_Release(&kv);
+ assertFalse(isEqual, "Expect test key-values to not be equal");
+
+ kv = parcKeyValue_Create(data->key1, data->value1);
+ isEqual = parcKeyValue_Equals(kv, data->testKV1) && !parcKeyValue_Equals(kv, data->testKV2);
+ parcKeyValue_Release(&kv);
+
+ assertTrue(isEqual, "Expect test key-values to be equal");
+
+ // NULL values
+ isEqual = parcKeyValue_Equals(data->testKV1, data->nullValue);
+ assertFalse(isEqual, "Expect NULL key-valuet to not be equal");
+
+ kv = parcKeyValue_Copy(data->nullValue);
+ isEqual = parcKeyValue_Equals(kv, data->nullValue);
+ assertTrue(isEqual, "Expect NULL key-valuet to not be equal");
+ parcKeyValue_Release(&kv);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Compare)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcKeyValue_Compare(NULL, NULL) == 0, "Expect 0 from comparing NULLs");
+ assertTrue(parcKeyValue_Compare(data->testKV1, NULL) > 0, "Expect result > 0 from comparing non-NULL to NULL");
+ assertTrue(parcKeyValue_Compare(NULL, data->testKV1) < 0, "Expect result < 0 from comparing NULL to non-NULL");
+
+ int result = parcKeyValue_Compare(data->testKV1, data->testKV2);
+ assertTrue(result < 0, "Expect compareison to be < 0");
+
+ result = parcKeyValue_Compare(data->testKV2, data->testKV1);
+ assertTrue(result > 0, "Expect compareison to be > 0");
+
+ // Mixed keys & values
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2);
+ result = parcKeyValue_Compare(kv, data->testKV1);
+ assertTrue(result == 0, "Expect comparison to be 0");
+
+ result = parcKeyValue_Compare(kv, data->testKV2);
+ assertTrue(result < 0, "Expect comparison to be < 0");
+
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ result = parcKeyValue_Compare(data->testKV1, data->nullValue);
+ assertTrue(result > 0, "Expect NULL key-value be > 0");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_HashCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCHashCode hash1 = parcKeyValue_HashCode(data->testKV1);
+ PARCHashCode hash2 = parcKeyValue_HashCode(data->testKV2);
+ assertFalse(hash1 == hash2, "Expect hash codes to be different");
+
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value1);
+ hash2 = parcKeyValue_HashCode(kv);
+ assertTrue(hash1 == hash2, "Expect hash codes to be equal");
+ parcKeyValue_Release(&kv);
+
+ // Mixed keys & values
+ kv = parcKeyValue_Create(data->key1, data->value2);
+ hash2 = parcKeyValue_HashCode(kv);
+ assertTrue(hash1 == hash2, "Expect hash codes to be equal");
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ PARCHashCode hash = parcKeyValue_HashCode(data->nullValue);
+ assertTrue(hash != 0, "Expect NULL key-value hash to != 0");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_EqualKeys)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ assertFalse(parcKeyValue_EqualKeys(data->testKV1, data->testKV2), "Expect keys to be different");
+
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2);
+
+ assertTrue(parcKeyValue_EqualKeys(data->testKV1, kv), "Expect keys to be equal");
+
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ assertFalse(parcKeyValue_EqualKeys(data->nullValue, data->testKV1), "Expect NULL key-value hash to != 0");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_SetKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcKeyValue_SetKey(data->testKV2, data->key1);
+
+ assertTrue(parcKeyValue_EqualKeys(data->testKV1, data->testKV2),
+ "Expect kv keys to be equal after SetKey");
+
+ // NULL value
+ parcKeyValue_SetKey(data->nullValue, data->key1);
+ assertTrue(parcKeyValue_EqualKeys(data->testKV1, data->nullValue),
+ "Expect kv keys to be equal after SetKey");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_SetValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcKeyValue_SetValue(data->testKV2, data->value1);
+
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1),
+ parcKeyValue_GetValue(data->testKV2)),
+ "Expect kv values to be equal after SetValue");
+
+ // NULL value
+ parcKeyValue_SetValue(data->testKV2, NULL);
+ assertNull(parcKeyValue_GetValue(data->testKV2),
+ "Expect NULL for testKV2 after SetValue");
+
+ parcKeyValue_SetValue(data->nullValue, data->value1);
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1),
+ parcKeyValue_GetValue(data->nullValue)),
+ "Expect kv values to be equal after SetValue");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCKeyValue *kv = parcKeyValue_Copy(data->testKV1);
+ assertTrue(parcKeyValue_Equals(kv, data->testKV1),
+ "Expect key-value copy to be equal to original key-value");
+
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ kv = parcKeyValue_Copy(data->nullValue);
+ assertTrue(parcKeyValue_Equals(kv, data->nullValue),
+ "Expect key-value copy to be equal to original key-value");
+
+ parcKeyValue_Release(&kv);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_KeyValue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_KeyedElement.c b/libparc/parc/algol/test/test_parc_KeyedElement.c
new file mode 100755
index 00000000..a6866437
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_KeyedElement.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_KeyedElement.c"
+
+#include <LongBow/unit-test.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_KeyedElement)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_KeyedElement)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_KeyedElement)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_GetData);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_SetData);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_CreateDestroy)
+{
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create("Some data", key1, keylen1);
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_GetData)
+{
+ char *initial_data = "some data here";
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create(initial_data, key1, keylen1);
+ char *data = parcKeyedElement_GetData(keyedElement);
+ assertTrue(initial_data == data, "We got different data from element");
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_GetKey)
+{
+ char *initial_data = "some data here";
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create(initial_data, key1, keylen1);
+ char *thekey = parcKeyedElement_GetKey(keyedElement);
+ size_t thekeylen = parcKeyedElement_GetKeyLen(keyedElement);
+ assertTrue(keylen1 == thekeylen, "We got different key size?");
+ assertTrue(memcmp(key1, thekey, keylen1) == 0, "We got different keys?");
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_SetData)
+{
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ char *initial_data = "some data here";
+
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create("Hello World", key1, keylen1);
+
+ parcKeyedElement_SetData(keyedElement, initial_data);
+ char *data = parcKeyedElement_GetData(keyedElement);
+ assertTrue(initial_data == data, "We got different data from element");
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_KeyedElement);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_LinkedList.c b/libparc/parc/algol/test/test_parc_LinkedList.c
new file mode 100644
index 00000000..294f2ea2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_LinkedList.c
@@ -0,0 +1,1192 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_LinkedList.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(PARCLinkedList)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(PARCLinkedList)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCLinkedList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcLinkedList_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcLinkedList_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcLinkedList_CreateRelease)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+ assertNotNull(deque, "Expected non-null result from parcLinkedList_Create()");
+
+ assertTrue(parcLinkedList_IsValid(deque), "Expected created PARCLinkedList to be valid.");
+
+ parcLinkedList_Release(&deque);
+ assertNull(deque, "Expected parcLinkedList_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcLinkedList_AcquireRelease)
+{
+ PARCLinkedList *original = parcLinkedList_Create();
+ assertNotNull(original, "Expected non-null result from parcLinkedList_Create()");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLinkedList_Acquire, original);
+
+ PARCLinkedList *reference = parcLinkedList_Acquire(original);
+ assertTrue(original == reference, "Expected the reference to be equal to the original.");
+
+ parcLinkedList_Release(&original);
+ assertNull(original, "Expected parcLinkedList_Release to null the pointer");
+
+ PARCBuffer *object = parcBuffer_Allocate(11);
+ parcLinkedList_Append(reference, object);
+ parcBuffer_Release(&object);
+
+ size_t expected = 1;
+ size_t actual = parcLinkedList_Size(reference);
+ assertTrue(expected == actual,
+ "Expected size %zd, actual %zd", expected, actual);
+ parcLinkedList_Release(&reference);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Append_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Append_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AppendAll);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AppendAll_None);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetLast);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_Three);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_IsEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Contains_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Contains_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveFirst_SingleElement);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveLast);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveNotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Head);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_HeadEmptyList);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Tail);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Middle);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Display_NULL);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveHead);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveMiddle);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveTail);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetEquals_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetEquals_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_AssertValid)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ parcLinkedList_AssertValid(list);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Append_One)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ PARCBuffer *object = parcBuffer_Allocate(11);
+ PARCLinkedList *actual = parcLinkedList_Append(list, object);
+ parcBuffer_Release(&object);
+
+ assertTrue(parcLinkedList_IsValid(list), "PARCLinkedList is invalid.");
+
+ assertTrue(list == actual, "Expected parcLinkedList_Append to return its argument.");
+ assertTrue(parcLinkedList_Size(list) == 1, "Expected size of 1, actual %zd", parcLinkedList_Size(list));
+
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Append_Two)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+
+ parcLinkedList_Append(deque, object1);
+ PARCLinkedList *actual = parcLinkedList_Append(deque, object2);
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Append to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque));
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_AppendAll)
+{
+ PARCLinkedList *other = parcLinkedList_Create();
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i);
+ parcLinkedList_Append(other, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ parcLinkedList_AppendAll(list, other);
+
+ assertTrue(parcLinkedList_Equals(list, other), "Expected equal lists.");
+
+ parcLinkedList_Release(&list);
+ parcLinkedList_Release(&other);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_AppendAll_None)
+{
+ PARCLinkedList *other = parcLinkedList_Create();
+
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ parcLinkedList_AppendAll(list, other);
+
+ assertTrue(parcLinkedList_Equals(list, other), "Expected equal lists.");
+
+ parcLinkedList_Release(&list);
+ parcLinkedList_Release(&other);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateDestroy)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+ assertNotNull(deque, "Expected non-null result from parcLinkedList_Create()");
+
+ parcLinkedList_Release(&deque);
+ assertNull(deque, "Expected parcLinkedList_Destroy to null the pointer");
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_HashCode)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ parcLinkedList_HashCode(deque);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_GetFirst)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *actual = parcLinkedList_GetFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, actual), "Order of objects in the list is wrong.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_GetLast)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *actual = parcLinkedList_GetLast(deque);
+ assertTrue(parcBuffer_Equals(object3, actual), "Order of objects in the list is wrong.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_One)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCLinkedList *actual = parcLinkedList_Prepend(deque, object1);
+ parcBuffer_Release(&object1);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Append to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 1, "Expected size of 1, actual %zd", parcLinkedList_Size(deque));
+ assertTrue(deque->head != NULL, "Expected head to be not null.");
+ assertTrue(deque->head == deque->tail, "Expected head to be equal to the tail.");
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_Two)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCLinkedList *actual = parcLinkedList_Prepend(deque, object1);
+ parcLinkedList_Prepend(deque, object1);
+ parcBuffer_Release(&object1);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Prepend to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque));
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_Three)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ parcLinkedList_Prepend(deque, object1);
+ parcLinkedList_Prepend(deque, object2);
+ PARCLinkedList *actual = parcLinkedList_Prepend(deque, object3);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Prepend to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 3, "Expected size of 3, actual %zd", parcLinkedList_Size(deque));
+
+ PARCBuffer *peek = parcLinkedList_GetFirst(deque);
+ assertTrue(parcBuffer_Equals(object3, peek), "Order of objects failed");
+
+ peek = parcLinkedList_GetLast(deque);
+ assertTrue(parcBuffer_Equals(object1, peek), "Order of objects failed");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveFirst)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcLinkedList_Append(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *peek = parcLinkedList_RemoveFirst(list);
+ assertTrue(parcObject_GetReferenceCount(peek) == 1, "Expected reference count to be 1.");
+ assertTrue(parcBuffer_GetUint32(peek) == 0, "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveFirst_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Prepend(deque, object1);
+
+ PARCBuffer *peek = parcLinkedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveLast)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcLinkedList_Append(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *peek = parcLinkedList_RemoveLast(list);
+ assertTrue(parcObject_GetReferenceCount(peek) == 1, "Expected reference count to be 1.");
+ assertTrue(parcBuffer_GetUint32(peek) == 999, "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveLast_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Prepend(deque, object1);
+
+ PARCBuffer *peek = parcLinkedList_RemoveLast(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Remove)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ parcLinkedList_Prepend(deque, object3);
+ parcLinkedList_Prepend(deque, object2);
+ parcLinkedList_Prepend(deque, object1);
+
+ bool found = parcLinkedList_Remove(deque, object2);
+ assertTrue(found, "Expected item to be found");
+ assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque));
+
+ PARCBuffer *peek;
+ peek = parcLinkedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek), "Object1 was not first in list");
+ parcBuffer_Release(&peek);
+
+ peek = parcLinkedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object3, peek), "Object3 was not second in list");
+ parcBuffer_Release(&peek);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveAtIndex)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ parcLinkedList_Prepend(list, object3);
+ parcLinkedList_Prepend(list, object2);
+ parcLinkedList_Prepend(list, object1);
+
+ PARCBuffer *actual = parcLinkedList_RemoveAtIndex(list, 1);
+
+ assertTrue(parcBuffer_Equals(object2, actual), "Wrong object returned from parcLinkedList_RemoveAtIndex");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&actual);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveNotFound)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+
+ parcLinkedList_Prepend(deque, object3);
+ parcLinkedList_Prepend(deque, object2);
+ parcLinkedList_Prepend(deque, object1);
+
+ bool found = parcLinkedList_Remove(deque, object4);
+ assertFalse(found, "Expected item to be not found");
+ assertTrue(parcLinkedList_Size(deque) == 3, "Expected size of 3, actual %zd", parcLinkedList_Size(deque));
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Size)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Prepend(deque, object1);
+ parcLinkedList_Prepend(deque, object2);
+ parcLinkedList_Prepend(deque, object3);
+
+ assertTrue(parcLinkedList_Size(deque) == 3,
+ "Expected 3, actual %zd", parcLinkedList_Size(deque));
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_IsEmpty)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ assertTrue(parcLinkedList_IsEmpty(deque), "Expected true.");
+ parcLinkedList_Prepend(deque, object1);
+ assertFalse(parcLinkedList_IsEmpty(deque), "Expected false.");
+
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_GetAtIndex)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *actual;
+ actual = parcLinkedList_GetAtIndex(deque, 0);
+ assertTrue(parcBuffer_Equals(actual, object1), "parcLinkedList_GetAtIndex failed");
+ actual = parcLinkedList_GetAtIndex(deque, 1);
+ assertTrue(parcBuffer_Equals(actual, object2), "parcLinkedList_GetAtIndex failed");
+ actual = parcLinkedList_GetAtIndex(deque, 2);
+ assertTrue(parcBuffer_Equals(actual, object3), "parcLinkedList_GetAtIndex failed");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_SetAtIndex)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *newObject = parcBuffer_WrapCString("Hello");
+
+ PARCBuffer *actual = parcLinkedList_SetAtIndex(deque, 0, newObject);
+ assertTrue(parcBuffer_Equals(actual, object1), "parcLinkedList_SetAtIndex failed to return the old value.");
+ parcBuffer_Release(&actual);
+
+ actual = parcLinkedList_GetAtIndex(deque, 0);
+ assertTrue(parcBuffer_Equals(actual, newObject), "parcLinkedList_SetAtIndex failed to set the new value.");
+
+ parcBuffer_Release(&newObject);
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Contains_True)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *list = parcLinkedList_Create();
+ parcLinkedList_Append(list, object1);
+ parcLinkedList_Append(list, object2);
+ parcLinkedList_Append(list, object3);
+
+ bool actual = parcLinkedList_Contains(list, object2);
+ assertTrue(actual, "Expected parcLinkedList_Contains to return true for object in the list");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Contains_False)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *list = parcLinkedList_Create();
+ parcLinkedList_Append(list, object1);
+ parcLinkedList_Append(list, object3);
+
+ bool actual = parcLinkedList_Contains(list, object2);
+ assertFalse(actual, "Expected parcLinkedList_Contains to return false for object not in the list");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Equals)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ PARCLinkedList *y = parcLinkedList_Create();
+ parcLinkedList_Append(y, object1);
+ parcLinkedList_Append(y, object2);
+ PARCLinkedList *z = parcLinkedList_Create();
+ parcLinkedList_Append(z, object1);
+ parcLinkedList_Append(z, object2);
+ PARCLinkedList *u1 = parcLinkedList_Create();
+ parcLinkedList_Append(u1, object2);
+ PARCLinkedList *u2 = parcLinkedList_Create();
+ parcLinkedList_Append(u2, object2);
+ parcLinkedList_Append(u2, object3);
+
+ parcObjectTesting_AssertEqualsFunction(parcLinkedList_Equals, x, y, z, u1, u2, NULL);
+
+ parcLinkedList_Release(&x);
+ parcLinkedList_Release(&y);
+ parcLinkedList_Release(&z);
+ parcLinkedList_Release(&u1);
+ parcLinkedList_Release(&u2);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Copy)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ PARCLinkedList *y = parcLinkedList_Copy(x);
+
+ assertTrue(parcLinkedList_Equals(x, y), "Expected the copy to be equal to the original.");
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+
+ parcLinkedList_Release(&y);
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Head)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_InsertAtIndex(x, 0, object4);
+
+ PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 0);
+
+ assertTrue(actual == object4, "Unexpected object at index 0");
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_HeadEmptyList)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+
+ parcLinkedList_InsertAtIndex(x, 0, object4);
+ assertTrue(x->head->object == object4, "Malformed linked list node does not contain the proper object reference");
+ assertTrue(x->head == x->tail, "Expected the list head and tail to be the same for a single element list.");
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 0);
+
+ assertTrue(actual == object4, "Unexpected object at index 0");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Tail)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_InsertAtIndex(x, 3, object4);
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 3);
+
+ assertTrue(actual == object4, "Unexpected object at index 3");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Middle)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_InsertAtIndex(x, 1, object4);
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ assertTrue(parcLinkedList_GetAtIndex(x, 0) == object1, "Unexpected object at index 1");
+ assertTrue(parcLinkedList_GetAtIndex(x, 1) == object4, "Unexpected object at index 1");
+ assertTrue(parcLinkedList_GetAtIndex(x, 2) == object2, "Unexpected object at index 1");
+ assertTrue(parcLinkedList_GetAtIndex(x, 3) == object3, "Unexpected object at index 1");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Display)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_Display(x, 0);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Display_NULL)
+{
+ parcLinkedList_Display(NULL, 0);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+
+ uint32_t expectedCount = 10;
+ for (uint32_t i = 0; i < expectedCount; i++) {
+ PARCBuffer *object = parcBuffer_Allocate(sizeof(int));
+ parcBuffer_PutUint32(object, i);
+ parcBuffer_Flip(object);
+ parcLinkedList_Append(x, object);
+ parcBuffer_Release(&object);
+ }
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ uint32_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_Remove)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < 5; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator));
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcIterator_Remove(iterator);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ iterator = parcLinkedList_CreateIterator(x);
+ assertFalse(parcIterator_HasNext(iterator), "Expected an interator on an empty list to not HaveNext");
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == 0, "List is not empty.");
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveHead)
+{
+ size_t listSize = 5;
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < listSize; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Display(x, 0);
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ if (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator);
+ size_t actual = parcBuffer_GetUint64(buffer);
+ assertTrue(actual == 0, "Expected %d, actual %zd", 0, actual);
+ parcIterator_Remove(iterator);
+ }
+ parcIterator_Release(&iterator);
+
+ iterator = parcLinkedList_CreateIterator(x);
+ assertTrue(parcIterator_HasNext(iterator), "Expected an interator on a non-empty list to HaveNext");
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x));
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveMiddle)
+{
+ size_t listSize = 5;
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < listSize; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ assertTrue(parcLinkedList_Size(x) == listSize, "Expected the list to be %zd, actual %zd", listSize, parcLinkedList_Size(x));
+
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ for (size_t i = 0; i <= listSize / 2; i++) {
+ if (parcIterator_HasNext(iterator)) {
+ parcIterator_Next(iterator);
+ }
+ }
+ parcIterator_Remove(iterator);
+
+ parcIterator_Release(&iterator);
+
+
+ iterator = parcLinkedList_CreateIterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ if (expected != (listSize / 2)) {
+ size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator));
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ }
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x));
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveTail)
+{
+ size_t listSize = 5;
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < listSize; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ assertTrue(parcLinkedList_Size(x) == listSize, "Expected the list to be %zd, actual %zd", listSize, parcLinkedList_Size(x));
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ for (size_t i = 0; i < listSize; i++) {
+ if (parcIterator_HasNext(iterator)) {
+ parcIterator_Next(iterator);
+ }
+ }
+ parcIterator_Remove(iterator);
+
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x));
+
+
+ iterator = parcLinkedList_CreateIterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator));
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_SetEquals_True)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ PARCLinkedList *y = parcLinkedList_Create();
+ parcLinkedList_Append(y, object2);
+ parcLinkedList_Append(y, object1);
+
+ PARCLinkedList *u1 = parcLinkedList_Create();
+ parcLinkedList_Append(u1, object2);
+
+ PARCLinkedList *u2 = parcLinkedList_Create();
+ parcLinkedList_Append(u2, object2);
+ parcLinkedList_Append(u2, object3);
+
+ assertTrue(parcLinkedList_SetEquals(x, y), "Expected to lists with the same elements to be equal regarless of order.");
+
+ parcLinkedList_Release(&x);
+ parcLinkedList_Release(&y);
+ parcLinkedList_Release(&u1);
+ parcLinkedList_Release(&u2);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_SetEquals_False)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+
+ PARCLinkedList *u1 = parcLinkedList_Create();
+ parcLinkedList_Append(u1, object2);
+
+ PARCLinkedList *u2 = parcLinkedList_Create();
+ parcLinkedList_Append(u2, object2);
+ parcLinkedList_Append(u2, object3);
+
+ assertFalse(parcLinkedList_SetEquals(x, u1), "Expected to lists without the same elements to be equal regarless of order.");
+
+ parcLinkedList_Release(&x);
+ parcLinkedList_Release(&u1);
+ parcLinkedList_Release(&u2);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _parcLinkedListNode_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _parcLinkedListNode_Create)
+{
+ PARCBuffer *object = parcBuffer_Allocate(10);
+ struct parc_linkedlist_node *previous = NULL;
+ struct parc_linkedlist_node *next = NULL;
+
+ struct parc_linkedlist_node *actual = _parcLinkedListNode_Create(object, previous, next);
+ parcBuffer_Release(&object);
+ _parcLinkedListNode_Destroy(NULL, &actual);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_Append);
+ LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_N2);
+ LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_CreateIterator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcLinkedList_Append)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ for (size_t i = 0; i < 100000; i++) {
+ parcLinkedList_Append(x, object1);
+ }
+
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcLinkedList_N2)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ for (size_t i = 0; i < 100000; i++) {
+ parcLinkedList_Append(x, object1);
+ }
+
+ for (size_t expected = 0; expected < parcLinkedList_Size(x); expected++) {
+ PARCBuffer *actual = (PARCBuffer *) parcLinkedList_GetAtIndex(x, expected);
+ assertTrue(parcBuffer_Equals(object1, actual), "Mismatched value in the list.");
+ }
+
+ parcBuffer_Release(&object1);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcLinkedList_CreateIterator)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+
+ uint32_t expectedCount = 100000;
+ for (uint32_t i = 0; i < expectedCount; i++) {
+ PARCBuffer *object = parcBuffer_Allocate(sizeof(int));
+ parcBuffer_PutUint32(object, i);
+ parcBuffer_Flip(object);
+ parcLinkedList_Append(x, object);
+ parcBuffer_Release(&object);
+ }
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ uint32_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcLinkedList_Release(&x);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCLinkedList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_List.c b/libparc/parc/algol/test/test_parc_List.c
new file mode 100644
index 00000000..59a7d136
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_List.c
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_List.c"
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(PARCList)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(PARCList);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+// LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARCList)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCList)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Add);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_AddAll);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcList_Release);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Equals_Contract_Deep);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_FromInitialCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_New);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Length);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_IsEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Add)
+{
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ parcList_Add(list, 0);
+ size_t actual = parcList_Size(list);
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_AddAll)
+{
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ void *elements[] = {
+ strdup("a"),
+ strdup("b"),
+ strdup("c"),
+ };
+
+ parcList_AddAll(list, 3, elements);
+ size_t actual = parcList_Size(list);
+
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Copy)
+{
+ char *a = strdup("apple");
+ char *b = strdup("bananna");
+ char *c = strdup("cherry");
+
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ parcList_Add(list, a);
+ parcList_Add(list, b);
+ parcList_Add(list, c);
+
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcList_Release)
+{
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ parcList_Release(&list);
+ assertNull(list, "Expected null.");
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Empty)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ PARCArrayList *b = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, b), "Equal values were expected to be equal");
+
+ parcArrayList_Destroy(&a);
+ parcArrayList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Same)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, a), "Expected the same array list to be equal to itself.");
+
+ parcArrayList_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Contract)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create(NULL);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create(NULL);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create(NULL);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+static bool
+stringEquals(void *x, void *y)
+{
+ return strcmp((char *) x, (char *) y) == 0;
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Contract_Deep)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u2, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_FromInitialCapacity)
+{
+ PARCArrayList *array = parcArrayList_Create_Capacity(NULL, parcArrayList_StdlibFreeFunction, 10);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(0 == actual, "Expected=%d, actual=%zu", 0, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Get)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ char *expected = strdup("Hello World");
+ parcArrayList_Add(array, expected);
+
+ char *actual = parcArrayList_Get(array, 0);
+
+ assertTrue(expected == actual, "Expected=%p, actual=%p", (void *) expected, (void *) actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_New)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ size_t size = parcArrayList_Size(array);
+ assertTrue(0 == size, "Expected %d actual=%zd", 0, size);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Length)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t size = parcArrayList_Size(array);
+ assertTrue(1 == size, "Expected %d actual=%zd", 1, size);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_IsEmpty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ assertTrue(parcArrayList_IsEmpty(array), "Expected a new array to be empty.");
+
+ parcArrayList_Add(array, 0);
+ assertFalse(parcArrayList_IsEmpty(array), "Expected an array with more than zero elements to be empty.");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 1, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 3, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 2, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_Empty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_InsertAtIndex(array, 0, (void *) 3);
+
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_First)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_InsertAtIndex(array, 0, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 2, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 1, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_Last)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 2, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 2, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 3, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 0);
+
+ assertTrue(removedElement == a, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 1);
+
+ assertTrue(removedElement == b, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 2);
+
+ assertTrue(removedElement == c, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 0);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 1);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 2);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, PARCList_InsertAtIndex_OutOfCapacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ longBowTestCase_SetClipBoardData(testCase, array);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+ parcArrayList_Destroy(&array);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARCList_InsertAtIndex_OutOfCapacity, .event = &LongBowAssertEvent)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+
+ parcArrayList_InsertAtIndex(array, 200, (void *) 3);
+}
+
+
+LONGBOW_TEST_FIXTURE(PARCList)
+{
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Add);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_AddCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_AddCollectionAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Contains);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_ContainsCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Equals);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_IsEmpty);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_GetAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Remove);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_RemoveCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_RetainCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_HashCode);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_IndexOf);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_LastIndexOf);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Copy);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Clear);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Destroy);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_RemoveAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_SetAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Size);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_SubList);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_ToArray);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(PARCList)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ longBowTestCase_Set(testCase, "linkedList", parcLinkedList_Create());
+ longBowTestCase_Set(testCase, "list", parcLinkedList_AsPARCList(longBowTestCase_Get(testCase, "linkedList")));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(PARCList)
+{
+ PARCLinkedList *linkedList = longBowTestCase_Get(testCase, "linkedList");
+ parcLinkedList_Release(&linkedList);
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ parcList_Release(&list);
+
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+//#include "test_parc_List_modular.c"
+
+LONGBOW_TEST_CASE(PARCList, parcList_Add)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+
+ size_t actual = parcList_Size(list);
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_AddCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_AddCollectionAtIndex)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Contains)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_ContainsCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Equals)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ PARCList *copy = parcList_Copy(list);
+
+ assertTrue(parcList_Equals(list, copy), "Expected copy to be equal to the original.");
+
+ parcList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_IsEmpty)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ assertTrue(parcList_IsEmpty(list), "Expected list to be empty.");
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_GetAtIndex)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ uint32_t actual = parcBuffer_GetUint32(parcList_GetAtIndex(list, 0));
+
+ assertTrue(actual == 0, "Expected %u, actual %u\n", 0, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Remove)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+
+ buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+
+ bool actual = parcList_Remove(list, buffer);
+ assertTrue(actual, "Expected element to have been found and removed.");
+
+ parcBuffer_Release(&buffer);
+
+ buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 3));
+
+ actual = parcList_Remove(list, buffer);
+ assertFalse(actual, "Expected element to have not been found and removed.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_RemoveCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_RetainCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_HashCode)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ parcList_HashCode(list);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_IndexOf)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ uint32_t expected = 10;
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 10));
+ size_t actual = parcList_IndexOf(list, buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual, "Expected %u, actual %zu", expected, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_LastIndexOf)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ uint32_t expected = 999;
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ size_t actual = parcList_LastIndexOf(list, buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual, "Expected %u, actual %zu", expected, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Copy)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ PARCList *copy = parcList_Copy(list);
+
+ assertTrue(parcList_Equals(list, copy), "Expected copy to be equal to the original.");
+
+ parcList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Clear)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ parcList_Clear(list);
+
+ assertTrue(parcList_IsEmpty(list), "Expected list to be empty.");
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Destroy)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ PARCList *copy = parcList_Copy(list);
+
+ parcList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_RemoveAtIndex)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *buffer = parcList_RemoveAtIndex(list, 0);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+ assertTrue(actual == 0, "Expected buffer 0.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_SetAtIndex)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("1");
+
+ PARCBuffer *oldValue = parcList_SetAtIndex(list, 50, buffer);
+
+ PARCBuffer *actual = parcList_GetAtIndex(list, 50);
+ assertTrue(parcBuffer_Equals(buffer, actual), "parcList_SetAtIndex set the wrong location.");
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&oldValue);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Size)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t size = parcArrayList_Size(array);
+ assertTrue(1 == size, "Expected %d actual=%zd", 1, size);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_SubList)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_ToArray)
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Memory.c b/libparc/parc/algol/test/test_parc_Memory.c
new file mode 100755
index 00000000..5fb18ce3
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Memory.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Memory.c"
+
+LONGBOW_TEST_RUNNER(parc_Memory)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Memory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Memory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_RoundUpToMultiple);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_RoundUpToCacheLine);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_AllocateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_MemAlign);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Reallocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_StringDuplicate);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Outstanding);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_SetInterface);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Format);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_RoundUpToMultiple)
+{
+ size_t actual = parcMemory_RoundUpToMultiple(14, 12);
+ assertTrue((actual % 12) == 0, "Expected %zd to be a multiple of %d", actual, 12);
+ assertTrue(24 == actual, "Expected 24, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(14, 20);
+ assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20);
+ assertTrue(20 == actual, "Expected 20, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(20, 20);
+ assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20);
+ assertTrue(20 == actual, "Expected 20, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(0, 20);
+ assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20);
+ assertTrue(20 == actual, "Expected 20, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(8, 0);
+ assertTrue(actual == 8, "Expected %d, actual %zd", 8, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_RoundUpToCacheLine)
+{
+ size_t actual = parcMemory_RoundUpToCacheLine(LEVEL1_DCACHE_LINESIZE - 1);
+ assertTrue((actual % LEVEL1_DCACHE_LINESIZE) == 0,
+ "Expected %zd to be a multiple of %d", actual, LEVEL1_DCACHE_LINESIZE);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Allocate)
+{
+ void *pointer;
+ pointer = parcMemory_Allocate(sizeof(int));
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_MemAlign)
+{
+ void *pointer;
+ int actual = parcMemory_MemAlign(&pointer, sizeof(void *), sizeof(int));
+ assertTrue(actual == 0, "Expected successful return value.");
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Reallocate)
+{
+ void *pointer;
+ int actual = parcMemory_MemAlign(&pointer, sizeof(void *), sizeof(int));
+ assertTrue(actual == 0, "Expected successful return value.");
+
+ pointer = parcMemory_Reallocate(pointer, sizeof(int) * 2);
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_AllocateAndClear)
+{
+ void *pointer;
+ pointer = parcMemory_AllocateAndClear(sizeof(int));
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ for (int i = 0; i < sizeof(int); i++) {
+ assertTrue(((char *) pointer)[i] == 0, "Expected cell to be zero.");
+ }
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_StringDuplicate)
+{
+ char *expected = "Hello";
+
+ char *actual = parcMemory_StringDuplicate(expected, strlen(expected));
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Outstanding)
+{
+ void *pointer;
+ pointer = parcMemory_Allocate(sizeof(int));
+
+ size_t expected = 1;
+ size_t actual = parcMemory_Outstanding();
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcMemory_Deallocate(&pointer);
+
+ expected = 0;
+ actual = parcMemory_Outstanding();
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_SetInterface)
+{
+ const PARCMemoryInterface *old = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ parcMemory_SetInterface(old);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Format)
+{
+ char *expected = "Hello World";
+ char *actual = parcMemory_Format("Hello %s", "World");
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate(&actual);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Memory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Network.c b/libparc/parc/algol/test/test_parc_Network.c
new file mode 100755
index 00000000..864fe25d
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Network.c
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Network.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <sys/un.h>
+
+LONGBOW_TEST_RUNNER(parc_Networking)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Networking)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Networking)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet4AddressAny);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet4Address_BuildString);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet6Address_BuildString);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_dashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_colons);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_Inet4Equals);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_colons);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseLinkAddress_BadScheme);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadLink);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadMixOfDashesAndDots);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadMixOfDotsAndDashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadSpecification);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseInet4Address);
+
+ LONGBOW_RUN_TEST_CASE(Global, parseMAC48Address);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_TooShort);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_Garbage);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_TooShort);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_ipv4);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_ipv6);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_hostname);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_LOCAL);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET4);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET6);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_IPX);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockInet4AddressAny)
+{
+ struct sockaddr_in *test_sock = parcNetwork_SockInet4AddressAny();
+
+ assertNotNull(test_sock, "Expected a not null pointer\n");
+ assertTrue(test_sock->sin_family == AF_INET, "Expecting sin_family to be AF_INET\n");
+ assertTrue(test_sock->sin_addr.s_addr == INADDR_ANY, "Expecting sin_addr.s_addr to be set to INADDR_ANY\n");
+#if defined(SIN6_LEN)
+ assertTrue(test_sock->sin_len == sizeof(struct sockaddr_in), "Expecting sockaddr.sin_len to be %zu not %hhu\n",
+ sizeof(struct sockaddr_in), test_sock->sin_len);
+#endif
+
+ parcMemory_Deallocate((void **) &test_sock);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockInet4Address_BuildString)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ struct sockaddr_in *address = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+#if defined(SIN6_LEN)
+ assertTrue(address->sin_len == sizeof(struct sockaddr_in), "Expecting sockaddr.sin_len to be %zu not %hhu\n",
+ sizeof(struct sockaddr_in), address->sin_len);
+#endif
+ parcNetwork_SockInet4Address_BuildString(address, composer);
+
+ char *expected = "inet4://127.0.0.1:1234";
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &address);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockInet6Address_BuildString)
+{
+ struct sockaddr_in6 *address = parcNetwork_SockInet6Address("2001:720:1500:1::a100", 1234, 0, 1);
+#if defined(SIN6_LEN)
+ assertTrue(address->sin6_len == sizeof(struct sockaddr_in6), "Expecting sockaddr.sin6_len to be %zu not %hhu\n",
+ sizeof(struct sockaddr_in6), address->sin6_len);
+#endif
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcNetwork_SockInet6Address_BuildString(address, composer);
+
+ char *expected = "inet6://[2001:720:1500:1::a100%1]:1234";
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &address);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_dashes)
+{
+ char *expected = "link://01-23-45-67-89-ab";
+
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcNetwork_LinkAddress_BuildString((unsigned char *) parcBuffer_Overlay(address, 0), parcBuffer_Remaining(address), composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_colons)
+{
+ char *expected = "link://01-23-45-67-89-ab";
+
+ PARCBuffer *address = parcNetwork_ParseLinkAddress("link://01:23:45:67:89:ab");
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcNetwork_LinkAddress_BuildString((unsigned char *) parcBuffer_Overlay(address, 0), parcBuffer_Remaining(address), composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dashes)
+{
+ char *expected = "link://01-23-45-67-89-ab";
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+ parcBuffer_Flip(address);
+
+ PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ parcBuffer_SetPosition(address, 0);
+ parcBuffer_SetLimit(address, 6);
+
+ parcBuffer_SetPosition(e, 0);
+ parcBuffer_SetLimit(e, 6);
+
+ assertTrue(parcBuffer_Equals(address, e),
+ "Expected result failed.");
+
+ parcBuffer_Release(&e);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_colons)
+{
+ char *expected = "link://01:23:45:67:89:ab";
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+
+ PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ parcBuffer_SetPosition(address, 0);
+ parcBuffer_SetPosition(e, 0);
+ parcBuffer_SetLimit(address, 6);
+ parcBuffer_SetLimit(e, 6);
+
+ assertTrue(parcBuffer_Equals(address, e),
+ "Expected result failed.");
+
+ parcBuffer_Release(&e);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots)
+{
+ char *expected = "link://0123.4567.89ab";
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+
+ PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ parcBuffer_SetPosition(address, 0);
+ parcBuffer_SetPosition(e, 0);
+ parcBuffer_SetLimit(address, 6);
+ parcBuffer_SetLimit(e, 6);
+
+ assertTrue(parcBuffer_Equals(address, e),
+ "Expected result failed.");
+
+ parcBuffer_Release(&e);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_ParseLinkAddress_BadScheme, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "asdf://";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadLink, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://";
+ parcNetwork_ParseLinkAddress(expected);
+ printf("Hello\n");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadSpecification, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://a";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadMixOfDashesAndDots, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://01-23-45.6789ab";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadMixOfDotsAndDashes, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://012345.67-89-ab";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE(Global, parseMAC48Address)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("01-23-45-67-89-ab", buffer);
+ assertTrue(actual, "Expected parcNetwork_ParseMAC48Address() to return true");
+
+ parcBuffer_Flip(buffer);
+
+ assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("01:23:45:67:89:ab", buffer);
+ assertTrue(actual, "Expected parcNetwork_ParseMAC48Address() to return true");
+ parcBuffer_Flip(buffer);
+
+ assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("01:23:45:67:89", buffer);
+ assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected buffer to be unmodified.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_Garbage)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("0x:23:45:67:89:ab", buffer);
+ assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("0123.4567.89ab", buffer);
+ assertTrue(actual, "Expected _parseLinkAddressDot() to return true");
+ parcBuffer_Flip(buffer);
+
+ assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("0123.4567", buffer);
+ assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseInet4Address)
+{
+ struct sockaddr_in *address = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+
+ PARCBufferComposer *composer = parcNetwork_SockInet4Address_BuildString(address, parcBufferComposer_Create());
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *addressURI = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ struct sockaddr_in *actual = parcNetwork_ParseInet4Address(addressURI);
+
+ assertTrue(parcNetwork_Inet4Equals(address, actual),
+ "Expected Addresses are not equal");
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &addressURI);
+ parcBufferComposer_Release(&composer);
+ parcMemory_Deallocate((void **) &address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_Inet4Equals)
+{
+ struct sockaddr_in *x = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+ struct sockaddr_in *y = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+ struct sockaddr_in *z = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+ struct sockaddr_in *u1 = parcNetwork_SockInet4Address("127.0.0.2", 1234);
+ struct sockaddr_in *u2 = parcNetwork_SockInet4Address("127.0.0.1", 4567);
+
+ parcObjectTesting_AssertEqualsFunction(parcNetwork_Inet4Equals, x, y, z, u1, u2);
+
+ parcMemory_Deallocate((void **) &x);
+ parcMemory_Deallocate((void **) &y);
+ parcMemory_Deallocate((void **) &z);
+ parcMemory_Deallocate((void **) &u1);
+ parcMemory_Deallocate((void **) &u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_ipv4)
+{
+ const char *ipv4 = "1.1.1.1";
+ unsigned short port = 5959;
+
+ struct sockaddr_in truth = {
+ .sin_family = PF_INET,
+ .sin_port = htons(port),
+ .sin_addr.s_addr = htonl(0x01010101)
+ };
+
+ struct sockaddr_in *test = (struct sockaddr_in *) parcNetwork_SockAddress(ipv4, port);
+ assertNotNull(test, "Got null address for %s port %u", ipv4, port);
+ assertTrue(truth.sin_family == test->sin_family, "wrong family, expected %d got %d", truth.sin_family, test->sin_family);
+ assertTrue(truth.sin_port == test->sin_port, "wrong port, expected %u got %u", truth.sin_port, test->sin_port);
+
+ assertTrue(memcmp(&truth.sin_addr, &test->sin_addr, sizeof(struct in_addr)) == 0, "struct in_addr did not compare");
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_ipv6)
+{
+ const char *ipv6 = "fe80::aa20:66ff:fe00:314a";
+ uint8_t truth_addr[16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0xaa, 0x20, 0x66, 0xff, 0xfe, 0x00, 0x31, 0x4a };
+
+ unsigned short port = 5959;
+
+ struct sockaddr_in6 truth = {
+ .sin6_family = PF_INET6,
+ .sin6_port = htons(port)
+ };
+
+ memcpy(&truth.sin6_addr, truth_addr, sizeof(truth.sin6_addr));
+
+
+ struct sockaddr_in6 *test = (struct sockaddr_in6 *) parcNetwork_SockAddress(ipv6, port);
+ if (test == NULL) {
+ testSkip("IPv6 is not supported in the runtime environment.");
+ }
+ assertTrue(truth.sin6_family == test->sin6_family, "wrong family, expected %d got %d", truth.sin6_family, test->sin6_family);
+ assertTrue(truth.sin6_port == test->sin6_port, "wrong port, expected %u got %u", truth.sin6_port, test->sin6_port);
+
+ assertTrue(memcmp(&truth.sin6_addr, &test->sin6_addr, sizeof(struct in6_addr)) == 0, "struct in_addr did not compare");
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_hostname)
+{
+ const char *name = "localhost";
+ unsigned short port = 5959;
+
+ struct sockaddr *test = parcNetwork_SockAddress(name, port);
+ assertNotNull(test, "Got null looking up '%s'", name);
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_LOCAL)
+{
+ struct sockaddr_un name;
+ name.sun_family = PF_LOCAL;
+
+ bool isLocal = parcNetwork_IsSocketLocal((struct sockaddr *) &name);
+ assertTrue(isLocal, "PF_LOCAL address did not return as local");
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_IPX)
+{
+ struct sockaddr_un name;
+ name.sun_family = PF_IPX;
+
+ bool isLocal = parcNetwork_IsSocketLocal((struct sockaddr *) &name);
+ assertFalse(isLocal, "Expected parcNetwork_IsSocketLocal(PF_PUP) to return false");
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET4)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900);
+ bool isLoopback = parcNetwork_IsSocketLocal(s);
+ assertTrue(isLoopback, "127.1.1.1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET6)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("::1", 5900);
+ bool isLoopback = parcNetwork_IsSocketLocal(s);
+ assertTrue(isLoopback, "::1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+
+// =======================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet6Local_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet6Local_False);
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet4Local_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet4Local_False);
+
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDot);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDot_TooShort);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_TooShort);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_Garbage);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet6Local_True)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("::1", 5900);
+
+ bool isLoopback = _isInet6Loopback((struct sockaddr_in6 *) s);
+ assertTrue(isLoopback, "::1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet6Local_False)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("fe80::aa20:66ff:fe00:1", 5900);
+
+ bool isLoopback = _isInet6Loopback((struct sockaddr_in6 *) s);
+ assertFalse(isLoopback, "fe80::aa20:66ff:fe00:1 should not be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet4Local_True)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900);
+
+ bool isLoopback = _isInet4Loopback((struct sockaddr_in *) s);
+ assertTrue(isLoopback, "127.1.1.1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet4Local_False)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("13.1.1.1", 5900);
+
+ bool isLoopback = _isInet4Loopback((struct sockaddr_in *) s);
+ assertFalse(isLoopback, "13.1.1.1 should not be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("01-23-45-67-89-ab", buffer);
+ assertNotNull(actual, "Expected _parseLinkAddressDashOrColon() to return non-NULL value");
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("01:23:45:67:89:ab", buffer);
+ assertNotNull(actual, "Expected _parseLinkAddressDashOrColon() to return non-NULL value");
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("01:23:45:67:89", buffer);
+ assertNull(actual, "Expected _parseLinkAddressDashOrColon() to return NULL value");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_Garbage)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("0x:23:45:67:89:ab", buffer);
+ assertNull(actual, "Expected _parseLinkAddressDashOrColon() to return NULL value");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDot)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDot("0123.4567.89ab", buffer);
+ assertNotNull(actual, "Expected _parseLinkAddressDot() to return non-NULL value");
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDot_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDot("0123.4567", buffer);
+ assertNull(actual, "Expected _parseLinkAddressDot() to return NULL value");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Networking);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Object.c b/libparc/parc/algol/test/test_parc_Object.c
new file mode 100755
index 00000000..687654fe
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Object.c
@@ -0,0 +1,1580 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Object.c"
+
+#include <inttypes.h>
+#include <sys/time.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+typedef struct {
+ int calledCount;
+ int val;
+} _dummy_object;
+
+typedef _dummy_object _DummyObject;
+
+static void
+_dummy_Destroy(_DummyObject **obj __attribute__((unused)))
+{
+}
+
+static _DummyObject *
+_dummy_Copy(const _DummyObject *obj);
+
+
+static bool
+_dummy_Equals(const _DummyObject *x, const _DummyObject *y)
+{
+ const _DummyObject *dummy1 = x;
+ const _DummyObject *dummy2 = y;
+ return (dummy1->calledCount == dummy2->calledCount);
+}
+
+static int
+_dummy_Compare(const _DummyObject *x, const _DummyObject *y)
+{
+ const _DummyObject *dummy1 = x;
+ const _DummyObject *dummy2 = y;
+ if (dummy1->calledCount == dummy2->calledCount) {
+ return 0;
+ } else if (dummy1->calledCount < dummy2->calledCount) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+static uint32_t
+_dummy_HashCode(const _DummyObject *obj)
+{
+ _DummyObject *dummy = (_DummyObject *) obj;
+ dummy->calledCount++;
+ return 1337;
+}
+
+static char *
+_dummy_ToString(const _DummyObject *x __attribute__((unused)))
+{
+ char *str = (char *) parcMemory_Allocate(6);
+ char *test = "dummy";
+ sprintf(str, "%s", test);
+ return str;
+}
+
+static PARCJSON *
+_dummy_ToJSON(const _DummyObject *x __attribute__((unused)))
+{
+ PARCJSON *json = parcJSON_ParseString("{ \"type\" : \"dummy\" }");
+ return json;
+}
+
+parcObject_Override(_DummyObject, PARCObject,
+ .destroy = (PARCObjectDestroy *) _dummy_Destroy,
+ .copy = (PARCObjectCopy *) _dummy_Copy,
+ .toString = (PARCObjectToString *) _dummy_ToString,
+ .equals = (PARCObjectEquals *) _dummy_Equals,
+ .compare = (PARCObjectCompare *) _dummy_Compare,
+ .hashCode = (PARCObjectHashCode *) _dummy_HashCode,
+ .toJSON = (PARCObjectToJSON *) _dummy_ToJSON);
+
+static _DummyObject *
+_dummy_Copy(const _DummyObject *obj)
+{
+ _DummyObject *newDummy = parcObject_CreateInstance(_DummyObject);
+ const _DummyObject *dummy = obj;
+ newDummy->calledCount = dummy->calledCount;
+ return newDummy;
+}
+
+typedef _dummy_object _DummyObjectNoHash;
+parcObject_ExtendPARCObject(_DummyObjectNoHash,
+ _dummy_Destroy,
+ _dummy_Copy,
+ _dummy_ToString,
+ _dummy_Equals,
+ _dummy_Compare,
+ NULL,
+ _dummy_ToJSON);
+
+static bool
+_meta_destructor_true(PARCObject **objPtr)
+{
+ return true;
+}
+
+static bool
+_meta_destructor_false(PARCObject **objPtr)
+{
+ (*objPtr) = NULL;
+ return false;
+}
+
+static PARCObject *
+_meta_copy(const PARCObject *ptr)
+{
+ _DummyObject *d = parcMemory_AllocateAndClear(sizeof(_DummyObject));
+ _DummyObject *xx = (_DummyObject *) ptr;
+ d->val = xx->val;
+ return d;
+}
+
+static bool
+_meta_equals(const PARCObject *x, const PARCObject *y)
+{
+ _DummyObject *xx = (_DummyObject *) x;
+ _DummyObject *yy = (_DummyObject *) y;
+ return (xx->val == yy->val);
+}
+
+static int
+_meta_compare(const PARCObject *x, const PARCObject *y)
+{
+ _DummyObject *xx = (_DummyObject *) x;
+ _DummyObject *yy = (_DummyObject *) y;
+
+ if (xx->val == yy->val) {
+ return 0;
+ } else if (xx->val < yy->val) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+static PARCHashCode
+_meta_hashCode(const PARCObject *ptr)
+{
+ _DummyObject *xx = (_DummyObject *) ptr;
+ return xx->val;
+}
+
+static char *
+_meta_toString(const PARCObject *ptr)
+{
+ _DummyObject *xx = (_DummyObject *) ptr;
+
+ char *result;
+ parcMemory_MemAlign((void **) &result, sizeof(void *), sizeof(char));
+ assertNotNull(result, "parcMemory_Allocate returned NULL");
+
+ char *p = result;
+ sprintf(result, "%d", xx->val);
+
+ return p;
+}
+
+static PARCJSON *
+_meta_toJson(const PARCObject *ptr)
+{
+ _DummyObject *xx = (_DummyObject *) ptr;
+
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddInteger(json, "value", xx->val);
+
+ return json;
+}
+
+static const PARCMemoryInterface *_originalMemoryProvider;
+
+LONGBOW_TEST_RUNNER(parcObject)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+ LONGBOW_RUN_TEST_FIXTURE(PARCObjectDescriptor);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(StaticObjects);
+ LONGBOW_RUN_TEST_FIXTURE(Meta);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Subclasses);
+ LONGBOW_RUN_TEST_FIXTURE(Fail);
+ LONGBOW_RUN_TEST_FIXTURE(Locking);
+ LONGBOW_RUN_TEST_FIXTURE(WaitNotify);
+ LONGBOW_RUN_TEST_FIXTURE(Synchronization);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _objectHeaderIsValid);
+ LONGBOW_RUN_TEST_CASE(Static, _parcObject_PrefixLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+struct timeval _testObject;
+
+parcObject_Override(_testObject, PARCObject);
+
+LONGBOW_TEST_CASE(Static, _objectHeaderIsValid)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ assertTrue(_parcObjectHeader_IsValid(header, object), "Expected _parcObject_HeaderHeaderIsValid to be valid");
+
+ parcObject_Release(&object);
+}
+
+LONGBOW_TEST_CASE(Static, _parcObject_PrefixLength)
+{
+ // Test that the result is a multiple of the alignment value and greater than the size of _PARCObjectHeader.
+
+ // Compute the power of 2 value of sizeof(void *)
+ unsigned int v = sizeof(void *);
+ unsigned int r = 0; // r will be lg(v)
+
+ while (v >>= 1) {
+ r++;
+ }
+ PARCObjectDescriptor descriptor;
+
+ for (int i = r; i < 20; i++) {
+ descriptor.objectAlignment = 1 << i;
+ size_t actual = _parcObject_PrefixLength(&descriptor);
+ assertTrue((actual & (descriptor.objectAlignment - 1)) == 0,
+ "Alignment needs to be a multiple of %u", descriptor.objectAlignment);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Acquire);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Release);
+// LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Acquire_Invalid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcObject_Acquire)
+{
+ struct timeval *expected = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcObject_Acquire, expected);
+ parcObject_Release((void **) &expected);
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcObject_Release)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Create);
+// LONGBOW_RUN_TEST_CASE(Global, parcObject_CreateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_IsValid_NotValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_IsInstanceOf);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Copy_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_GetReferenceCount);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Display_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Display_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_GetDescriptor);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Release)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Create)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+}
+
+//LONGBOW_TEST_CASE(Global, parcObject_CreateAndClear)
+//{
+// struct timeval *time = parcObject_CreateAndClear(struct timeval);
+// parcObject_AssertValid(time);
+//
+// time->tv_sec = 1;
+// time->tv_usec = 2;
+//
+// PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+// assertTrue(count == 0, "Expected reference count to be zero");
+// assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+//}
+
+LONGBOW_TEST_CASE(Global, parcObject_IsValid)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ assertTrue(parcObject_IsValid(object), "Expected valid PARCObject");
+
+ parcObject_Release(&object);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_IsInstanceOf)
+{
+ _DummyObject *dummy1 = parcObject_CreateInstance(_DummyObject);
+ assertTrue(parcObject_IsInstanceOf(dummy1, &PARCObject_Descriptor),
+ "Expected _DummyObject to be an instance of PARCObject");
+
+ parcObject_Release((PARCObject **) &dummy1);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_IsValid_NotValid)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ PARCObject *alias = object;
+ parcObject_Release(&object);
+ assertFalse(parcObject_IsValid(object), "Expected invalid PARCObject");
+ assertFalse(parcObject_IsValid(alias), "Expected invalid PARCObject");
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Copy_Default)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ struct timeval *copy = parcObject_Copy(time);
+
+ parcObject_AssertValid(copy);
+
+ assertTrue(copy->tv_sec == 1, "Expected tv_sec to equal 1");
+ assertTrue(copy->tv_usec == 2, "Expected tv_usec to equal 2");
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &copy);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(copy == 0, "Expected memory pointer to be NULL after destroy.");
+
+ parcObject_Release((PARCObject *) &time);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Copy)
+{
+ _DummyObject *dummy1 = parcObject_CreateInstance(_DummyObject);
+ dummy1->calledCount = 100;
+
+ _DummyObject *dummy2 = parcObject_Copy(dummy1);
+
+ assertTrue(dummy2->calledCount == dummy1->calledCount,
+ "Expected called counts to be the same. Got %d, expected %d.", dummy1->calledCount, dummy2->calledCount);
+
+ parcObject_Release((PARCObject **) &dummy1);
+ parcObject_Release((PARCObject **) &dummy2);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Compare_Default)
+{
+ struct timeval *time1 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time1);
+
+ time1->tv_sec = 1;
+ time1->tv_usec = 2;
+
+ struct timeval *time2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time2);
+
+ time2->tv_sec = 1;
+ time2->tv_usec = 2;
+
+ int compareResult = parcObject_Compare(time1, time2);
+ assertTrue(compareResult == 0, "Expected objects to compare equal. Comparison result: %d", compareResult);
+ compareResult = parcObject_Compare(time1, time1);
+ assertTrue(compareResult == 0, "Expected same object to be equal since they have identical pointer addresses. Comparison result: %d", compareResult);
+
+ parcObject_Release((PARCObject *) &time1);
+ parcObject_Release((PARCObject *) &time2);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Compare_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override",
+ sizeof(struct timeval), sizeof(void*),
+ true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+ struct timeval *time1 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_AssertValid(time1);
+
+ time1->tv_sec = 1;
+ time1->tv_usec = 2;
+
+ struct timeval *time2 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_AssertValid(time2);
+
+ time2->tv_sec = 1;
+ time2->tv_usec = 2;
+
+ int compareResult = parcObject_Compare(time1, time2);
+ assertTrue(compareResult == 0, "Expected objects to compare equal. Comparison result: %d", compareResult);
+ compareResult = parcObject_Compare(time1, time1);
+ assertTrue(compareResult == 0, "Expected same object to be equal since they have identical pointer addresses. Comparison result: %d", compareResult);
+
+ parcObject_Release((PARCObject *) &time1);
+ parcObject_Release((PARCObject *) &time2);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Compare)
+{
+ _DummyObject *value = parcObject_CreateAndClearInstance(_DummyObject);
+ _DummyObject *equality[2];
+ equality[0] = parcObject_CreateAndClearInstance(_DummyObject);
+ equality[1] = NULL;
+ _DummyObject *lesser[2];
+ lesser[0] = parcObject_CreateAndClearInstance(_DummyObject);
+ lesser[1] = NULL;
+
+ _DummyObject *greater[2];
+ greater[0] = parcObject_CreateAndClearInstance(_DummyObject);
+ greater[1] = NULL;
+
+ value->calledCount = 50;
+ equality[0]->calledCount = 50;
+ lesser[0]->calledCount = 10;
+ greater[0]->calledCount = 80;
+
+ parcObjectTesting_AssertCompareTo(parcObject_Compare, value, equality, lesser, greater);
+
+ parcObject_Release((void **) &value);
+ parcObject_Release((void **) &equality[0]);
+ parcObject_Release((void **) &lesser[0]);
+ parcObject_Release((void **) &greater[0]);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Equals_Default)
+{
+ struct timeval *x = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ memset(x, 0, sizeof(struct timeval));
+ x->tv_sec = 1;
+ x->tv_usec = 2;
+
+ struct timeval *y = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ memset(y, 0, sizeof(struct timeval));
+ y->tv_sec = 1;
+ y->tv_usec = 2;
+
+ assertTrue(parcObject_Equals(x, y), "Expected equality");
+
+ struct timeval *z = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ z->tv_sec = 1;
+ z->tv_usec = 2;
+
+ struct timeval *unequal1 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ unequal1->tv_sec = 1;
+ unequal1->tv_usec = 1;
+
+ struct timeval *unequal2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ unequal2->tv_sec = 0;
+ unequal2->tv_usec = 0;
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, NULL);
+
+ parcObject_Release((PARCObject *) &x);
+ parcObject_Release((PARCObject *) &y);
+ parcObject_Release((PARCObject *) &z);
+ parcObject_Release((PARCObject *) &unequal1);
+ parcObject_Release((PARCObject *) &unequal2);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Equals_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ struct timeval *x = parcObject_CreateAndClearInstanceImpl(descriptor);
+ memset(x, 0, sizeof(struct timeval));
+ x->tv_sec = 1;
+ x->tv_usec = 2;
+
+ struct timeval *y = parcObject_CreateAndClearInstanceImpl(descriptor);
+ memset(y, 0, sizeof(struct timeval));
+ y->tv_sec = 1;
+ y->tv_usec = 2;
+
+ assertTrue(parcObject_Equals(x, y), "Expected equality");
+
+ struct timeval *z = parcObject_CreateAndClearInstanceImpl(descriptor);
+ z->tv_sec = 1;
+ z->tv_usec = 2;
+
+ struct timeval *unequal1 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ unequal1->tv_sec = 1;
+ unequal1->tv_usec = 1;
+
+ struct timeval *unequal2 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ unequal2->tv_sec = 0;
+ unequal2->tv_usec = 0;
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, NULL);
+
+ parcObject_Release((PARCObject *) &x);
+ parcObject_Release((PARCObject *) &y);
+ parcObject_Release((PARCObject *) &z);
+ parcObject_Release((PARCObject *) &unequal1);
+ parcObject_Release((PARCObject *) &unequal2);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Equals)
+{
+ _DummyObject *x = parcObject_CreateInstance(_DummyObject);
+ x->calledCount = 100;
+ _DummyObject *y = parcObject_CreateInstance(_DummyObject);
+ y->calledCount = 100;
+ _DummyObject *z = parcObject_CreateInstance(_DummyObject);
+ z->calledCount = 100;
+
+ _DummyObject *unequal1 = parcObject_CreateInstance(_DummyObject);
+ unequal1->calledCount = 50;
+
+ PARCObject *unequal2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+
+ PARCObjectDescriptor dummyMeta2 = parcObject_DescriptorName(_DummyObject);
+ _DummyObject *unequal3 = parcObject_CreateAndClearInstanceImpl(&dummyMeta2);
+ unequal3->calledCount = 100;
+
+ PARCObject *unequal4 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, unequal3, unequal4, NULL);
+
+ parcObject_Release((PARCObject **) &x);
+ parcObject_Release((PARCObject **) &y);
+ parcObject_Release((PARCObject **) &z);
+ parcObject_Release((PARCObject **) &unequal1);
+ parcObject_Release((PARCObject **) &unequal2);
+ parcObject_Release((PARCObject **) &unequal3);
+ parcObject_Release((PARCObject **) &unequal4);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_HashCode_Default)
+{
+ struct timeval *time = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCHashCode hashCode = parcObject_HashCode(time);
+ PARCHashCode expected = parcHashCode_Hash((void *) time, sizeof(struct timeval));
+ assertTrue(hashCode == expected, "Hash codes do not match. Got %" PRIPARCHashCode ", expected %" PRIPARCHashCode ".", hashCode, expected);
+
+ parcObject_Release((PARCObject *) &time);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_HashCode_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+ struct timeval *time = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCHashCode hashCode = parcObject_HashCode(time);
+ PARCHashCode expected = parcHashCode_Hash((void *) time, sizeof(struct timeval));
+ assertTrue(hashCode == expected, "Hash codes do not match. Got %" PRIPARCHashCode ", expected %" PRIPARCHashCode ".", hashCode, expected);
+
+ parcObject_Release((PARCObject *) &time);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_HashCode)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ PARCHashCode hashCode = parcObject_HashCode(dummy);
+ assertTrue(hashCode == 1337, "Expected hashcode to be 1337, got %" PRIPARCHashCode, hashCode);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToString)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ char *strRep = parcObject_ToString(dummy);
+ assertTrue(strcmp(strRep, "dummy") == 0, "Expected 'dummy' string representation, got %s", strRep);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToString_Default)
+{
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(&_DummyObject_Descriptor);
+
+ char *strRep = parcObject_ToString(dummy);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToString_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(descriptor);
+
+ char *strRep = parcObject_ToString(dummy);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcObject_Release((PARCObject **) &dummy);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToJSON_Default)
+{
+ size_t expectedSize = sizeof(struct timeval);
+ PARCObject *memory = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+
+ PARCJSON *json = parcObject_ToJSON(memory);
+
+ const PARCJSONPair *lengthPair = parcJSON_GetPairByName(json, "objectLength");
+ PARCJSONValue *lengthValue = parcJSONPair_GetValue(lengthPair);
+ uint64_t actualLength = parcJSONValue_GetInteger(lengthValue);
+
+ const PARCJSONPair *alignmentPair = parcJSON_GetPairByName(json, "objectAlignment");
+ PARCJSONValue *alignmentValue = parcJSONPair_GetValue(alignmentPair);
+ int alignment = (int) parcJSONValue_GetInteger(alignmentValue);
+
+ assertTrue(actualLength >= expectedSize,
+ "Expected length to be >= %zd, actual %" PRIu64 "", expectedSize, actualLength);
+ assertTrue(alignment == sizeof(void *), "Expected objectAlignment to be %zd, got %d",
+ sizeof(void *), alignment);
+
+ parcJSON_Release(&json);
+ parcObject_Release(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToJSON)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ PARCJSON *json = parcObject_ToJSON(dummy);
+ char *strRep = parcJSON_ToString(json);
+ assertTrue(strcmp(strRep, "{ \"type\" : \"dummy\" }") == 0, "Expected fixed JSON object with a specific string representation, got %s", strRep);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcJSON_Release(&json);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToJSON_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ size_t expectedSize = sizeof(struct timeval);
+ PARCObject *memory = parcObject_CreateAndClearInstanceImpl(descriptor);
+
+ PARCJSON *json = parcObject_ToJSON(memory);
+ const PARCJSONPair *lengthPair = parcJSON_GetPairByName(json, "objectLength");
+ PARCJSONValue *lengthValue = parcJSONPair_GetValue(lengthPair);
+ uint64_t actualLength = parcJSONValue_GetInteger(lengthValue);
+
+ const PARCJSONPair *alignmentPair = parcJSON_GetPairByName(json, "objectAlignment");
+ PARCJSONValue *alignmentValue = parcJSONPair_GetValue(alignmentPair);
+ int alignment = (int) parcJSONValue_GetInteger(alignmentValue);
+
+ assertTrue(actualLength >= expectedSize,
+ "Expected length to be >= %zd, actual %" PRIu64 "", expectedSize, actualLength);
+ assertTrue(alignment == sizeof(void *), "Expected objectAlignment to be %zd, got %d",
+ sizeof(void *), alignment);
+
+ parcJSON_Release(&json);
+ parcObject_Release(&memory);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_GetReferenceCount)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ PARCReferenceCount refCount = parcObject_GetReferenceCount(dummy);
+ assertTrue(refCount == 1, "Expected reference count to be 1, got %" PRIu64 "", refCount);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Display_Default)
+{
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(&_DummyObject_Descriptor);
+ parcObject_Display(dummy, 0);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Display_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_Display(dummy, 0);
+ parcObject_Release((PARCObject **) &dummy);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Display)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ parcObject_Display(dummy, 0);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_GetDescriptor)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ const PARCObjectDescriptor *descriptor = parcObject_GetDescriptor(dummy);
+
+ assertTrue(descriptor == &_DummyObject_Descriptor, "Expected pointer to _DummyObject_Descriptor");
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_FIXTURE(Subclasses)
+{
+ LONGBOW_RUN_TEST_CASE(Subclasses, parcObject_Copy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Subclasses)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Subclasses)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Subclasses, parcObject_Copy)
+{
+ const PARCObjectDescriptor *objectType =
+ parcObjectDescriptor_Create("Dummy", sizeof(_DummyObject), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ parcObject_SetDescriptor(dummy, objectType);
+
+ dummy->calledCount = 100;
+
+ _DummyObject *dummy2 = parcObject_Copy(dummy);
+
+ assertTrue(dummy2->calledCount == dummy->calledCount,
+ "Expected called counts to be the same. Got %d, expected %d.", dummy->calledCount, dummy2->calledCount);
+
+ parcObject_Release((PARCObject **) &dummy);
+ parcObject_Release((PARCObject **) &dummy2);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &objectType);
+}
+
+LONGBOW_TEST_FIXTURE(Locking)
+{
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_TryLock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_Lock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_TryLock_AlreadyLockedSameThread);
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_Lock_AlreadyLocked);
+}
+static uint32_t initialAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Locking)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ initialAllocations = parcMemory_Outstanding();
+
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ longBowTestCase_SetClipBoardData(testCase, dummy);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Locking)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ parcObject_Release((PARCObject **) &dummy);
+
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Locking, parcObject_TryLock_Unlock)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_TryLock(dummy);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcObject_Unlock(dummy);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertFalse(actual, "Expected parcObject_IsLocked to be false.");
+}
+
+LONGBOW_TEST_CASE(Locking, parcObject_Lock_Unlock)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_Lock(dummy);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcObject_Unlock(dummy);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertFalse(actual, "Expected parcObject_IsLocked to be false.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Locking, parcObject_TryLock_AlreadyLockedSameThread, .event = &LongBowTrapCannotObtainLockEvent)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_TryLock(dummy);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcObject_TryLock(dummy);
+
+ assertFalse(actual, "Expected parcObject_TryLock to fail when already locked by the same thread.");
+
+ actual = parcObject_Unlock(dummy);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Locking, parcObject_Lock_AlreadyLocked, .event = &LongBowTrapCannotObtainLockEvent)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_Lock(dummy);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertTrue(actual, "Expected locked object to indicate being locked.");
+
+ parcObject_Lock(dummy);
+}
+
+LONGBOW_TEST_FIXTURE(WaitNotify)
+{
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotify);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotify2);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitUntil);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitFor);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotifyAll);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(WaitNotify)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(WaitNotify)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// Just wait until told to wakeup, then increment a counter and unlock.
+static void *
+waiter(void *data)
+{
+ _DummyObject *dummy = data;
+
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ assertTrue(parcObject_IsLocked(dummy), "%p object %p not locked.", (void *) pthread_self(), (void *) dummy);
+ parcObject_Wait(dummy);
+
+ dummy->val++;
+ parcObject_Unlock(dummy);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotify)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+ pthread_t thread_C;
+ pthread_create(&thread_A, NULL, waiter, dummy);
+ pthread_create(&thread_B, NULL, waiter, dummy);
+ pthread_create(&thread_C, NULL, waiter, dummy);
+
+ while (dummy->val != 3) {
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ parcObject_Notify(dummy);
+ parcObject_Unlock(dummy);
+ }
+
+ pthread_join(thread_A, NULL);
+// pthread_join(thread_B, NULL);
+// pthread_join(thread_C, NULL);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotifyAll)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+ pthread_t thread_C;
+ pthread_create(&thread_A, NULL, waiter, dummy);
+ pthread_create(&thread_B, NULL, waiter, dummy);
+ pthread_create(&thread_C, NULL, waiter, dummy);
+
+ while (dummy->val != 3) {
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ parcObject_NotifyAll(dummy);
+ parcObject_Unlock(dummy);
+ }
+
+ pthread_join(thread_A, NULL);
+// pthread_join(thread_B, NULL);
+// pthread_join(thread_C, NULL);
+
+ assertTrue(dummy->val == 3, "Expected the counter to be 3, actual %d", dummy->val);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+static void *
+decrement(void *data)
+{
+ _DummyObject *dummy = data;
+
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ while (dummy->val < 12) {
+ parcObject_Wait(dummy);
+ dummy->val--;
+ }
+ parcObject_Unlock(dummy);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotify2)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ pthread_t thread_A;
+ pthread_create(&thread_A, NULL, decrement, dummy);
+
+ dummy->val = 2;
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ while (dummy->val <= 12) {
+ parcObject_Notify(dummy);
+ dummy->val += 2;
+ }
+ parcObject_Unlock(dummy);
+
+ pthread_join(thread_A, NULL);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitUntil)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ time_t now;
+ time_t then;
+ time(&then);
+ if (parcObject_Lock(dummy)) {
+ struct timespec future;
+ future.tv_sec = then + 3;
+ future.tv_nsec = 0;
+ parcObject_WaitUntil(dummy, &future);
+
+ time(&now);
+ long expected = now - 1; // Subtract 1 because the future may have been computed at the 999,999,999 nanosecond mark.
+ assertTrue(now >= expected, "Expected now %ld, to be later than than %ld", now, expected);
+ parcObject_Unlock(dummy);
+ }
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitFor)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ time_t now;
+ time_t then;
+ time(&then);
+ if (parcObject_Lock(dummy)) {
+ uint64_t nanoSeconds = 1000000000;
+ parcObject_WaitFor(dummy, nanoSeconds);
+
+ time(&now);
+ now++; // Advance now by 1 because of the precision mismatch between gettimeofday and nanosecond resolution of parcObject_WaitFor
+ assertTrue(now >= then + (nanoSeconds / 1000000000),
+ "Expected now %ld, to be later than time %" PRIu64, now, then + (nanoSeconds / 1000000000));
+ parcObject_Unlock(dummy);
+ }
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_FIXTURE(Fail)
+{
+}
+
+typedef struct {
+ PARCObject *value;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Fail)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->value = parcObject_CreateInstance(_DummyObjectNoHash);
+ if (data->value == NULL) {
+ return LONGBOW_STATUS_SETUP_FAILED;
+ }
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Fail)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ parcObject_Release(&data->value);
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, _parcObject_PrefixLength_10000000);
+ LONGBOW_RUN_TEST_CASE(Performance, parcObject_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(Performance, parcObject_Create);
+ LONGBOW_RUN_TEST_CASE(Performance, parcObject_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, _parcObject_PrefixLength_10000000)
+{
+ // Test that the result is a multiple of the alignment value and greater than the size of _PARCObjectHeader.
+
+ // Compute the power of 2 value of sizeof(void *)
+ unsigned int v = sizeof(void *);
+ unsigned int r = 0; // r will be lg(v)
+
+ while (v >>= 1) {
+ r++;
+ }
+
+ PARCObjectDescriptor descriptor;
+
+ for (int i = r; i < 20; i++) {
+ descriptor.objectAlignment = 1 << i;
+ size_t actual = _parcObject_PrefixLength(&descriptor);
+ assertTrue((actual & (descriptor.objectAlignment - 1)) == 0,
+ "Alignment needs to be a multiple of %u", descriptor.objectAlignment);
+ }
+}
+
+#define OBJECT_COUNT 10000000
+#define OBJECT_SIZE 1200
+
+typedef struct { char bytes[OBJECT_SIZE]; } PerformanceObject;
+
+parcObject_Override(PerformanceObject, PARCObject);
+
+LONGBOW_TEST_CASE(Performance, parcObject_CreateRelease)
+{
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ PARCObject *object = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor);
+
+ PARCObject *object1 = parcObject_Acquire(object);
+ PARCObject *object2 = parcObject_Acquire(object);
+ parcObject_Release(&object1);
+ parcObject_Release(&object2);
+
+ parcObject_Release(&object);
+ }
+}
+
+void *objects[OBJECT_COUNT];
+
+LONGBOW_TEST_CASE(Performance, parcObject_AcquireRelease)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor);
+
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ objects[i] = parcObject_Acquire(object);
+ }
+
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ parcObject_Release(&objects[i]);
+ }
+
+ parcObject_Release(&object);
+}
+
+LONGBOW_TEST_CASE(Performance, parcObject_Create)
+{
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ objects[i] = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor);
+ }
+
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ parcObject_Release(&objects[i]);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Meta)
+{
+ LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_True);
+ LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_False);
+ LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_None);
+
+ LONGBOW_RUN_TEST_CASE(Meta, parcObjectDescriptor_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Meta)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ _DummyObject *data;
+ parcMemory_MemAlign((void **) &data, sizeof(void *), sizeof(_DummyObject));
+ data->val = 10;
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Meta)
+{
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Meta, parcObjectDescriptor_Create)
+{
+ const PARCObjectDescriptor *interface = parcObjectDescriptor_Create("Meta",
+ sizeof(struct timeval), sizeof(void*),
+ true,
+ _meta_destructor_true, NULL, _meta_copy, _meta_toString,
+ _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor, NULL);
+
+ assertNotNull(interface, "Expected interface instance to be allocated correctly.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface);
+ assertNull(interface, "Expected parcObjectDescriptor_Destroy to NULL the input pointer");
+}
+
+LONGBOW_TEST_CASE(Meta, _metaDestructor_True)
+{
+ const PARCObjectDescriptor *interface =
+ parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ _meta_destructor_true, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor, NULL);
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ bool actual = _parcObject_Destructor(interface, (PARCObject **) &data);
+
+ assertTrue(actual, "Expected destructor to return true.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface);
+}
+
+LONGBOW_TEST_CASE(Meta, _metaDestructor_False)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ _meta_destructor_false, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor, NULL);
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ bool actual = _parcObject_Destructor(descriptor, (PARCObject **) &data);
+
+ assertNull(data, "Expected destructor function to have been called to nullify the reference.");
+ assertFalse(actual, "Expected destructor to return false.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Meta, _metaDestructor_None)
+{
+ const PARCObjectDescriptor *interface = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ _parcObject_Destructor(interface, (void **) &data);
+
+ assertNotNull(data, "Expected destructor function to have been called to nullify the reference.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface);
+}
+
+LONGBOW_TEST_FIXTURE(PARCObjectDescriptor)
+{
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_Create);
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_CreateExtension);
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetSuperType);
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetTypeState);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(PARCObjectDescriptor)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(PARCObjectDescriptor)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ uint32_t outstandingAllocations = parcMemory_Outstanding() - initialAllocations;
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_Create)
+{
+ const PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_CreateExtension)
+{
+ PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+
+ PARCObjectDescriptor *extension = parcObjectDescriptor_CreateExtension(descriptor, "Extension");
+
+ parcObjectDescriptor_Destroy(&extension);
+ parcObjectDescriptor_Destroy(&descriptor);
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetSuperType)
+{
+ PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+
+ const PARCObjectDescriptor *superType = parcObjectDescriptor_GetSuperType(descriptor);
+
+ assertTrue(superType == &PARCObject_Descriptor, "Expected a pointer to PARCObject_Descriptor");
+
+ parcObjectDescriptor_Destroy(&descriptor);
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetTypeState)
+{
+ PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals,
+ _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor,
+ (PARCObjectTypeState *) &PARCObject_Descriptor);
+
+ PARCObjectTypeState *state = parcObjectDescriptor_GetTypeState(descriptor);
+
+ assertTrue(state == &PARCObject_Descriptor, "Expected a pointer to PARCObject_Descriptor");
+
+ parcObjectDescriptor_Destroy(&descriptor);
+}
+
+LONGBOW_TEST_FIXTURE(StaticObjects)
+{
+ LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_WrapImpl);
+ LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_InitInstanceImpl);
+ LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_InitAndClearInstanceImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(StaticObjects)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(StaticObjects)
+{
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(StaticObjects, parcObject_WrapImpl)
+{
+ char *origin = (char[parcObject_TotalSize(sizeof(void*), 10)]) { 0 };
+
+ PARCObject *result = parcObject_WrapImpl(origin, &parcObject_DescriptorName(PARCObject));
+
+ parcObject_AssertValid(result);
+
+ parcObject_Release(&result);
+}
+
+PARCObject *globalObject = parcObject_Instance(PARCObject, sizeof(void*), 10);
+
+LONGBOW_TEST_CASE(StaticObjects, parcObject_InitInstanceImpl)
+{
+ parcObject_InitInstanceImpl(globalObject, &PARCObject_Descriptor);
+
+ parcObject_AssertValid(globalObject);
+
+// parcObject_Release(&globalObject);
+}
+
+LONGBOW_TEST_CASE(StaticObjects, parcObject_InitAndClearInstanceImpl)
+{
+ parcObject_InitAndClearInstanceImpl(globalObject, &PARCObject_Descriptor);
+
+ parcObject_AssertValid(globalObject);
+
+// parcObject_Release(&globalObject);
+}
+
+LONGBOW_TEST_FIXTURE(Synchronization)
+{
+ LONGBOW_RUN_TEST_CASE(Synchronization, parcObject_SynchronizeBegin);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Synchronization)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Synchronization)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Synchronization, parcObject_SynchronizeBegin)
+{
+ PARCObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ bool result = parcObject_BarrierSet(dummy);
+ assertTrue(result, "Expected parcObject_BarrierSet to always return true.");
+
+ _PARCObjectHeader *header = _parcObject_Header(dummy);
+ assertTrue(header->barrier, "Expected the header barrier to be set.");
+
+ result = parcObject_BarrierUnset(dummy);
+ assertFalse(result, "Expected parcObject_BarrierUnset to always return false.");
+ assertFalse(header->barrier, "Expected the header barrier to NOT be set.");
+
+ parcObject_Release(&dummy);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcObject);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
diff --git a/libparc/parc/algol/test/test_parc_PathName.c b/libparc/parc/algol/test/test_parc_PathName.c
new file mode 100755
index 00000000..b596aaa2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_PathName.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *
+ */
+#include "../parc_PathName.c"
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SafeMemory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+#define PATH_SEGMENT "A"
+
+LONGBOW_TEST_RUNNER(parc_PathName)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_PathName)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_PathName)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_Create);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_Release);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcPathName_Create)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ parcPathName_Release(&pathName);
+ assertNull(pathName, "Expected parcPathName_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcPathName_Release)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ parcPathName_Release(&pathName);
+ assertNull(pathName, "Expected parcPathName_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcPathName_AcquireRelease)
+{
+ PARCPathName *original = parcPathName_Create();
+ assertNotNull(original, "Expected non-null result from parcPathName_Create()");
+
+ PARCPathName *reference = parcPathName_Acquire(original);
+ assertTrue(original == reference, "Expected the reference to be equal to the original.");
+
+ parcPathName_Release(&original);
+ assertNull(original, "Expected parcDeque_Release to null the pointer");
+
+ parcPathName_Append(reference, (void *) "Hello");
+ size_t expected = 1;
+ size_t actual = parcPathName_Size(reference);
+ assertTrue(expected == actual,
+ "Expected size %zd, actual %zd", expected, actual);
+ parcPathName_Release(&reference);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Create);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Append);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Prepend);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_IsAbsolute);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_MakeAbsolute);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_AbsolutePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_AbsolutePath_Limited);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_RelativePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_ToString_AbsolutePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_ToString_RelativePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Head);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Tail);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Tail_ExceedsLength);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Copy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Size)
+{
+ char *path = "/a/b/c";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+ assertTrue(parcPathName_Size(pathName) == 3, "Expected 3, actual %zu", parcPathName_Size(pathName));
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Prepend)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ size_t size = 1000;
+
+ char expected[10];
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", i);
+ parcPathName_Prepend(pathName, expected);
+ }
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ size_t actual = parcPathName_Size(pathName);
+ assertTrue(size == actual,
+ "Expected %zd, actual %zd", size, actual);
+
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", size - i - 1);
+ char *segment = parcDeque_GetAtIndex(pathName->path, i);
+ assertTrue(strcmp(segment, expected) == 0,
+ "Expected %s, actual %s", expected, segment);
+ }
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Append)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ size_t size = 1000;
+
+ char expected[10];
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", i);
+ parcPathName_Append(pathName, expected);
+ }
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ size_t actual = parcPathName_Size(pathName);
+ assertTrue(size == actual,
+ "Expected %zd, actual %zd", size, actual);
+
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", i);
+ char *segment = parcDeque_GetAtIndex(pathName->path, i);
+ assertTrue(strcmp(segment, expected) == 0,
+ "Expected %s, actual %s", expected, segment);
+ }
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Create)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ parcPathName_Release(&pathName);
+ assertNull(pathName, "Expected parcPathName_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_IsAbsolute)
+{
+ char *path = "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/aa/bb/cc/dd/ee/ff/gg/hh/ii/jj/kk/ll/mm/nn/oo/pp/qq/rr/ss/tt/uu/vv/ww/xx/yy/zz";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(parcPathName_IsAbsolute(pathName), "Expected the PARCPathName to be absolute.");
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_MakeAbsolute)
+{
+#define PATH "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z"
+ char *expected = PATH;
+ PARCPathName *pathName = parcPathName_Parse(expected);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative.");
+
+ parcPathName_MakeAbsolute(pathName, true);
+
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp("/" PATH, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Parse_AbsolutePath)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ for (int i = 0; i < 1000; i++) {
+ parcBufferComposer_Format(composer, "/%d", i);
+ }
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *path = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp(path, actual) == 0, "Expected %s, actual %s", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &path);
+
+ parcPathName_Release(&pathName);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Parse_AbsolutePath_Limited)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ for (int i = 0; i < 10; i++) {
+ parcBufferComposer_Format(composer, "/%d", i);
+ }
+ parcBufferComposer_Format(composer, "?hello world");
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *path = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ size_t limit = strchr(path, '?') - path;
+ PARCPathName *pathName = parcPathName_ParseToLimit(limit, path);
+
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+ path[limit] = 0;
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp(path, actual) == 0, "Expected %s, actual %s", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &path);
+
+ parcPathName_Release(&pathName);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Parse_RelativePath)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ for (int i = 0; i < 1000; i++) {
+ parcBufferComposer_Format(composer, "%d/", i);
+ }
+ parcBufferComposer_Format(composer, "%d", 1000);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *expected = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ PARCPathName *pathName = parcPathName_Parse(expected);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative.");
+
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &expected);
+
+ parcPathName_Release(&pathName);
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_ToString_AbsolutePath)
+{
+ char *path = "/a/b/c";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+ char *actual = parcPathName_ToString(pathName);
+
+ assertTrue(strcmp(path, actual) == 0, "Expected '%s' actual '%s'", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_ToString_RelativePath)
+{
+ char *path = "a/b/c";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative.");
+
+ char *actual = parcPathName_ToString(pathName);
+
+ assertTrue(strcmp(path, actual) == 0, "Expected '%s' actual '%s'", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Head)
+{
+ PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ assertNotNull(original, "Expected a non-null pointer");
+
+ PARCPathName *expected = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ PARCPathName *actual = parcPathName_Head(original, 3);
+
+ assertTrue(parcPathName_Equals(expected, actual),
+ "expected did not match actual");
+
+ parcPathName_Release(&original);
+ parcPathName_Release(&expected);
+ parcPathName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Tail)
+{
+ PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ assertNotNull(original, "Expected a non-null pointer");
+
+ PARCPathName *expected = parcPathName_Parse(PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ PARCPathName *actual = parcPathName_Tail(original, 3);
+
+ assertTrue(parcPathName_Equals(expected, actual),
+ "expected did not match actual");
+
+ parcPathName_Release(&original);
+ parcPathName_Release(&expected);
+ parcPathName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Tail_ExceedsLength)
+{
+ PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ assertNotNull(original, "Expected a non-null pointer");
+
+ PARCPathName *actual = parcPathName_Tail(original, 10000000);
+
+ parcPathName_MakeAbsolute(original, false);
+
+ assertTrue(parcPathName_Equals(original, actual),
+ "expected did not match actual");
+
+ parcPathName_Release(&original);
+ parcPathName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Equals)
+{
+ PARCPathName *x = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *y = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *z = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *u1 = parcPathName_Parse("/a/b/c/d/e");
+ PARCPathName *u2 = parcPathName_Parse("/a/b/c/");
+ PARCPathName *u3 = parcPathName_Parse("a/b/c/");
+
+ parcObjectTesting_AssertEqualsFunction(parcPathName_Equals, x, y, z, u1, u2, u3, NULL);
+
+ parcPathName_Release(&x);
+ parcPathName_Release(&y);
+ parcPathName_Release(&z);
+ parcPathName_Release(&u1);
+ parcPathName_Release(&u2);
+ parcPathName_Release(&u3);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Copy)
+{
+ PARCPathName *x = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *y = parcPathName_Copy(x);
+
+ assertTrue(parcPathName_Equals(x, y), "Expected the copy to be equal to the original.");
+
+ parcPathName_Release(&x);
+ parcPathName_Release(&y);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PathName);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_PriorityQueue.c b/libparc/parc/algol/test/test_parc_PriorityQueue.c
new file mode 100644
index 00000000..d42066e4
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_PriorityQueue.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include <config.h>
+#include <inttypes.h>
+
+#include "../parc_PriorityQueue.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_PriorityQueue)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_PriorityQueue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_PriorityQueue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Add);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Add_Expand);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Clear);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Clear_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_ParcFreeDestroyer);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Peek);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Poll);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Peek_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Poll_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Uint64CompareTo);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Add)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ assertTrue(parcPriorityQueue_Size(queue) == count, "Wrong size got %zu expected %zu", parcPriorityQueue_Size(queue), count);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Add_Expand)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ size_t capacity = queue->capacity;
+ for (int i = 0; i <= capacity; i++) {
+ parcPriorityQueue_Add(queue, &capacity);
+ }
+
+ assertTrue(capacity < queue->capacity, "Did not expand queue before %zu after %zu", capacity, queue->capacity);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Clear)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ parcPriorityQueue_Clear(queue);
+
+ assertTrue(parcPriorityQueue_Size(queue) == 0, "Wrong size got %zu expected %d", parcPriorityQueue_Size(queue), 0);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Clear_Destroy)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ uint64_t *value = parcMemory_Allocate(sizeof(uint64_t));
+ assertNotNull(value, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint64_t));
+ *value = 1;
+ parcPriorityQueue_Add(queue, value);
+
+ parcPriorityQueue_Clear(queue);
+
+ assertTrue(parcPriorityQueue_Size(queue) == 0, "Wrong size got %zu expected %d", parcPriorityQueue_Size(queue), 0);
+ parcPriorityQueue_Destroy(&queue);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after clear with destroy: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_ParcFreeDestroyer)
+{
+ size_t before_balance = parcMemory_Outstanding();
+ uint64_t *a = parcMemory_Allocate(sizeof(uint64_t));
+ assertNotNull(a, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint64_t));
+ *a = 1;
+ parcPriorityQueue_ParcFreeDestroyer((void **) &a);
+ size_t after_balance = parcMemory_Outstanding();
+ assertTrue(a == NULL, "Did not null double pointer");
+ assertTrue(before_balance == after_balance, "Memory imbalance after destroy: before %zu after %zu", before_balance, after_balance);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Peek)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ uint64_t *test = parcPriorityQueue_Peek(queue);
+
+ assertTrue(*test == 50, "Wrong head element, expected 50 got %" PRIu64 "", *test);
+ assertTrue(parcPriorityQueue_Size(queue) == count, "Queue should not have shunk, size %zu expected %zu", parcPriorityQueue_Size(queue), count);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Poll)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ uint64_t *test = parcPriorityQueue_Poll(queue);
+
+ assertTrue(*test == 50, "Wrong head element, expected 50 got %" PRIu64 "", *test);
+ assertTrue(queue->size == count - 1, "Queue should have shunk, size %zu expected %zu", queue->size, count - 1);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Peek_Empty)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t *test = parcPriorityQueue_Peek(queue);
+ assertNull(test, "Peek on empty queue should return null, got %p", (void *) test);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Poll_Empty)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t *test = parcPriorityQueue_Poll(queue);
+ assertNull(test, "Poll on empty queue should return null, got %p", (void *) test);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Size)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Uint64CompareTo)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_BubbleUp_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_BubbleUp_False);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_Expand);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_LeftChildIndex);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_ParentIndex);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_RightChildIndex);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_Swap);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleDown);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_False);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case2_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_BubbleUp_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ _bubbleUp(queue, 1);
+ assertTrue(queue->array[0].data == &data[1], "Element 6 did not make it to the root");
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_BubbleUp_False)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 60 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ _bubbleUp(queue, 1);
+ assertTrue(queue->array[0].data == &data[0], "Element 60 did not stay as child");
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_Expand)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ size_t before_capacity = queue->capacity;
+ _expand(queue);
+ size_t after_capacity = queue->capacity;
+
+ assertTrue(before_capacity < after_capacity, "Expected after capacity %zu to be larger than before %zu", after_capacity, before_capacity);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_LeftChildIndex)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_ParentIndex)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_RightChildIndex)
+{
+ testUnimplemented("");
+}
+
+/**
+ * Swaps two elements
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_Swap)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ _swap(queue, 0, 1);
+ assertTrue(queue->array[0].data == &data[1], "array[0] does not equal data[1]: %p != %p",
+ (void *) queue->array[0].data, (void *) &data[1]);
+ assertTrue(queue->array[1].data == &data[0], "array[1] does not equal data[0]: %p != %p",
+ (void *) queue->array[1].data, (void *) &data[0]);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests each case in TrickleDown:
+ * - right child exists, then
+ * - no right child, only left child, then
+ * - no child
+ *
+ * 60 50
+ * / \ / \
+ * 70 50 ====> 70 55
+ * / \ / \ / \ / \
+ * 71 72 55 x 71 72 60 x
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleDown)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+
+ queue->size = 6;
+ for (int i = 0; i < queue->size; i++) {
+ queue->array[i].data = &data[i];
+ }
+
+ _trickleDown(queue, 0);
+ assertTrue(*((uint64_t *) queue->array[0].data) == 50,
+ "Root not 50, got %" PRIu64 "\n",
+ (uint64_t) *((uint64_t *) queue->array[0].data));
+ assertTrue(*((uint64_t *) queue->array[2].data) == 55,
+ "Right not 55, got %" PRIu64 "\n",
+ (uint64_t) *((uint64_t *) queue->array[2].data));
+ assertTrue(*((uint64_t *) queue->array[5].data) == 60,
+ "Last not 60, got %" PRIu64 "\n",
+ (uint64_t) *((uint64_t *) queue->array[5].data));
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the TRUE case of this condition
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ size_t nextElementIndex = _trickleLeftChild(queue, 0, 1);
+ assertTrue(nextElementIndex == 1, "nextElementIndex should have been left child 1, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the FALSE case of this condition
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_False)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 6, 50 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ size_t nextElementIndex = _trickleLeftChild(queue, 0, 1);
+ assertTrue(nextElementIndex == 0, "nextElementIndex should have been root 0, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+
+/**
+ * Tests the TRUE case
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 9, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->array[2].data = &data[2];
+ queue->size = 3;
+
+ size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2);
+ assertTrue(nextElementIndex == 2, "nextElementIndex should have been right 2, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the FALSE case
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_False)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+
+ // r.value not < n.value
+ uint64_t data[] = { 6, 9, 50 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->array[2].data = &data[2];
+ queue->size = 3;
+
+ size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2);
+ assertTrue(nextElementIndex == 0, "nextElementIndex should have been root 0, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the TRUE case
+ *
+ * Case 2: Right child exists and r.value < n.value && l.value <= r.value
+ * In this case swap(n.index, l.index) and set n.index = l.index
+ * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant.
+ * 50 6
+ * / \ ===> / \
+ * 6 9 50 9
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case2_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6, 9 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->array[2].data = &data[2];
+ queue->size = 3;
+
+ size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2);
+ assertTrue(nextElementIndex == 1, "nextElementIndex should have been left 1, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PriorityQueue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Properties.c b/libparc/parc/algol/test/test_parc_Properties.c
new file mode 100644
index 00000000..994b8d8e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Properties.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Properties.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Properties)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Specialized);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Properties)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Properties)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCProperties *instance = parcProperties_Create();
+ assertNotNull(instance, "Expected non-null result from parcProperties_Create();");
+
+ parcObjectTesting_AssertAcquire(instance);
+
+ parcProperties_Release(&instance);
+ assertNull(instance, "Expected null result from parcProperties_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Copy)
+{
+ PARCProperties *instance = parcProperties_Create();
+ PARCProperties *copy = parcProperties_Copy(instance);
+ assertTrue(parcProperties_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcProperties_Release(&instance);
+ parcProperties_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Display)
+{
+ PARCProperties *instance = parcProperties_Create();
+ parcProperties_SetProperty(instance, "foo", "bar");
+ parcProperties_SetProperty(instance, "xyzzy", "plugh");
+
+ parcProperties_Display(instance, 0);
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Equals)
+{
+ PARCProperties *x = parcProperties_Create();
+ PARCProperties *y = parcProperties_Create();
+ PARCProperties *z = parcProperties_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcProperties_Release(&x);
+ parcProperties_Release(&y);
+ parcProperties_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_HashCode)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_IsValid)
+{
+ PARCProperties *instance = parcProperties_Create();
+ assertTrue(parcProperties_IsValid(instance), "Expected parcProperties_Create to result in a valid instance.");
+
+ parcProperties_Release(&instance);
+ assertFalse(parcProperties_IsValid(instance), "Expected parcProperties_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_ToJSON)
+{
+ PARCProperties *instance = parcProperties_Create();
+
+ parcProperties_SetProperty(instance, "foo", "bar");
+ PARCJSON *json = parcProperties_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_ToString)
+{
+ PARCProperties *instance = parcProperties_Create();
+
+ parcProperties_SetProperty(instance, "foo", "bar");
+ parcProperties_SetProperty(instance, "bar", "baz");
+ char *string = parcProperties_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcProperties_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialized)
+{
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_SetProperty);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetProperty);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetPropertyDefault);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetAsBoolean_true);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetAsBoolean_false);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialized)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialized)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_SetProperty)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "bar";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ const char *actual = parcProperties_GetProperty(instance, "foo");
+ assertTrue(strcmp("bar", actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetProperty)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "bar";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ const char *actual = parcProperties_GetProperty(instance, "foo");
+ assertTrue(strcmp("bar", actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetPropertyDefault)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "bar";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ const char *actual = parcProperties_GetPropertyDefault(instance, "blurfl", "defaultValue");
+ assertTrue(strcmp("defaultValue", actual) == 0, "Expected %s, actual %s", "defaultValue", actual);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetAsBoolean_true)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "true";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ bool actual = parcProperties_GetAsBoolean(instance, "foo", false);
+ assertTrue(actual, "Expected true");
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetAsBoolean_false)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "false";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ bool actual = parcProperties_GetAsBoolean(instance, "foo", true);
+ assertFalse(actual, "Expected false");
+
+ parcProperties_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Properties);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/algol/test/test_parc_RandomAccessFile.c b/libparc/parc/algol/test/test_parc_RandomAccessFile.c
new file mode 100644
index 00000000..796b69d8
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_RandomAccessFile.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_RandomAccessFile.c"
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcRandomAccessFile_RandomAccessFile)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parcRandomAccessFile_RandomAccessFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parcRandomAccessFile_RandomAccessFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ assertNotNull(instance, "Expected non-null result from parcRandomAccessFile_Open();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcRandomAccessFile_Acquire, instance);
+
+ parcRandomAccessFile_Release(&instance);
+ assertNull(instance, "Expected null result from parcRandomAccessFile_Release();");
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Display);
+ // XXX: Disable this test until fixed
+ //LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Display)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ parcRandomAccessFile_Display(instance, 0);
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Equals)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+
+ sprintf(filename, "%s/tmpfileX", temporaryDirectory);
+ PARCFile *fileX = parcFile_Create(filename);
+
+ sprintf(filename, "%s/tmpfileY", temporaryDirectory);
+ PARCFile *fileY = parcFile_Create(filename);
+
+ sprintf(filename, "%s/tmpfileZ", temporaryDirectory);
+ PARCFile *fileZ = parcFile_Create(filename);
+
+ PARCRandomAccessFile *x = parcRandomAccessFile_Open(fileX);
+ PARCRandomAccessFile *y = parcRandomAccessFile_Open(fileY);
+ PARCRandomAccessFile *z = parcRandomAccessFile_Open(fileZ);
+ parcFile_Release(&fileX);
+ parcFile_Release(&fileY);
+ parcFile_Release(&fileZ);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcRandomAccessFile_Close(x);
+ parcRandomAccessFile_Close(y);
+ parcRandomAccessFile_Close(z);
+
+ parcRandomAccessFile_Release(&x);
+ parcRandomAccessFile_Release(&y);
+ parcRandomAccessFile_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_IsValid)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ parcFile_CreateNewFile(file);
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+ assertTrue(parcRandomAccessFile_IsValid(instance), "Expected parcRandomAccessFile_Create to result in a valid instance.");
+
+ parcRandomAccessFile_Release(&instance);
+ assertFalse(parcRandomAccessFile_IsValid(instance), "Expected parcRandomAccessFile_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_ToJSON)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ PARCJSON *json = parcRandomAccessFile_ToJSON(instance);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, "fname");
+ PARCJSONValue *value = parcJSONPair_GetValue(pair);
+ PARCBuffer *buffer = parcJSONValue_GetString(value);
+
+ char *string = parcBuffer_ToString(buffer);
+ assertTrue(strcmp(filename, string) == 0, "The file was stored correctly");
+
+ parcMemory_Deallocate(&string);
+
+ parcJSON_Release(&json);
+
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_ToString)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ char *string = parcRandomAccessFile_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcRandomAccessFile_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Read);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Write);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Seek);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Read)
+{
+ char *fname = "tmpfile";
+
+ PARCFile *file = parcFile_Create(fname);
+
+ parcFile_CreateNewFile(file);
+ FILE *fp = fopen(fname, "w");
+ fseek(fp, 0, SEEK_SET);
+
+ uint8_t data[128];
+ for (int i = 0; i < 128; i++) {
+ data[i] = i;
+ }
+ fwrite(data, 1, 128, fp);
+ fclose(fp);
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(128);
+ size_t numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+
+ parcBuffer_Flip(buffer);
+ uint8_t *bytes = parcBuffer_Overlay(buffer, parcBuffer_Remaining(buffer));
+ assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcRandomAccessFile_Close(instance);
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Write)
+{
+ char *fname = "tmpfile";
+
+ PARCFile *file = parcFile_Create(fname);
+
+ parcFile_CreateNewFile(file);
+
+ uint8_t data[128];
+ for (int i = 0; i < 128; i++) {
+ data[i] = i;
+ }
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ PARCBuffer *buffer = parcBuffer_Allocate(128);
+ parcBuffer_PutArray(buffer, 128, data);
+ parcBuffer_Flip(buffer);
+ size_t numBytes = parcRandomAccessFile_Write(instance, buffer);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+ parcBuffer_Release(&buffer);
+
+ parcRandomAccessFile_Close(instance);
+ parcRandomAccessFile_Release(&instance);
+
+ uint8_t bytes[128];
+ FILE *fp = fopen(fname, "r");
+ numBytes = fread(bytes, 1, 128, fp);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+
+ fclose(fp);
+
+ assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal");
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Seek)
+{
+ char *fname = "tmpfile";
+
+ PARCFile *file = parcFile_Create(fname);
+
+ parcFile_CreateNewFile(file);
+ FILE *fp = fopen(fname, "w");
+ fseek(fp, 0, SEEK_SET);
+
+ uint8_t data[128];
+ for (int i = 0; i < 128; i++) {
+ data[i] = i;
+ }
+ fwrite(data, 1, 128, fp);
+ fclose(fp);
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ PARCBuffer *buffer = parcBuffer_Allocate(128);
+ parcRandomAccessFile_Seek(instance, 64, PARCRandomAccessFilePosition_Start);
+ size_t numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 64, "Expected 64 bytes to be read, but got %zu", numBytes);
+
+ parcRandomAccessFile_Seek(instance, 0, PARCRandomAccessFilePosition_End);
+ parcBuffer_Flip(buffer);
+ numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 0, "Expected 0 bytes to be read, but got %zu", numBytes);
+
+ parcRandomAccessFile_Seek(instance, 0, PARCRandomAccessFilePosition_Start);
+ parcBuffer_Flip(buffer);
+ numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+
+ parcBuffer_Release(&buffer);
+ parcRandomAccessFile_Close(instance);
+ parcRandomAccessFile_Release(&instance);
+
+ parcFile_Release(&file);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcRandomAccessFile_RandomAccessFile);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c b/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c
new file mode 100644
index 00000000..19e250f8
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_ReadOnlyBuffer.c"
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_ReadableBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Getters);
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_ReadableBuffer)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ReadableBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Create);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease);
+// LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease_TooMany);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_NULL);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_WithOffset);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Create)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected initial limit to be 10.");
+
+ parcReadOnlyBuffer_Release(&actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_NULL)
+{
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(parcBuffer_Wrap(NULL, 10, 0, 10));
+ assertNull(actual, "Expected parcReadOnlyBuffer_Wrap to return NULL");
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == sizeof(array) / sizeof(array[0]), "Expected initial limit to be 10.");
+
+ parcReadOnlyBuffer_Release(&actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_WithOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 3, 10);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+ parcBuffer_Release(&buffer);
+ assertTrue(parcReadOnlyBuffer_Capacity(actual) == 10, "Expected initial capacity to be 3.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected initial limit to be 3.");
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 3, "Expected initial position to be 0.");
+
+ parcReadOnlyBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ PARCReadOnlyBuffer *expected = parcReadOnlyBuffer_Create(buffer);
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Acquire(expected);
+
+ assertTrue(expected == actual, "Expected %p, actual %p", (void *) expected, (void *) actual);
+
+ parcReadOnlyBuffer_Release(&expected);
+ assertTrue(expected == NULL, "Expected parcReadOnlyBuffer_Release to NULL the pointer.");
+ parcReadOnlyBuffer_Release(&actual);
+ assertTrue(actual == NULL, "Expected parcReadOnlyBuffer_Release to NULL the pointer.");
+ parcBuffer_Release(&buffer);
+}
+
+//LONGBOW_TEST_CASE_EXPECTS(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease_TooMany, .event = &LongBowTrapIllegalValue)
+//{
+// PARCBuffer *buffer = parcBuffer_Allocate(10);
+// PARCReadOnlyBuffer *expected = parcReadOnlyBuffer_Create(buffer);
+// PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Acquire(expected);
+// PARCReadOnlyBuffer *alias = actual;
+//
+// parcBuffer_Release(&buffer);
+// parcReadOnlyBuffer_Release(&expected);
+// parcReadOnlyBuffer_Release(&actual);
+// parcReadOnlyBuffer_Release(&alias); // this must fail.
+//}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Array);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_ArrayOffset);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Clear);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Flip);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_GetByte);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_GetArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_HasRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Mark);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Overlay);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Position);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Remaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Rewind);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit_TruncatePosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetPosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Equals)
+{
+ PARCReadOnlyBuffer *x = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCReadOnlyBuffer *y = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCReadOnlyBuffer *z = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCReadOnlyBuffer *u1 = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10);
+ PARCReadOnlyBuffer *u2 = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9);
+ PARCReadOnlyBuffer *u3 = parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9);
+ PARCReadOnlyBuffer *u4 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 2);
+ PARCReadOnlyBuffer *u5 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+ PARCReadOnlyBuffer *u6 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+
+ parcObjectTesting_AssertEqualsFunction(parcReadOnlyBuffer_Equals, x, y, z, u1, u2, u3, u4, u5, u6, NULL);
+
+ parcReadOnlyBuffer_Release(&x);
+ parcReadOnlyBuffer_Release(&y);
+ parcReadOnlyBuffer_Release(&z);
+ parcReadOnlyBuffer_Release(&u1);
+ parcReadOnlyBuffer_Release(&u2);
+ parcReadOnlyBuffer_Release(&u3);
+ parcReadOnlyBuffer_Release(&u4);
+ parcReadOnlyBuffer_Release(&u5);
+ parcReadOnlyBuffer_Release(&u6);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Array)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *readWriteBuffer = parcBuffer_Wrap(expected, 10, 0, 10);
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Create(readWriteBuffer);
+ parcBuffer_Release(&readWriteBuffer);
+
+ PARCByteArray *array = parcReadOnlyBuffer_Array(buffer);
+ uint8_t *actual = parcByteArray_Array(array);
+
+ parcReadOnlyBuffer_Release(&buffer);
+
+ assertTrue(expected == actual,
+ "Expected %p, actual %p",
+ (void *) expected, (void *) actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Flip)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+
+ parcReadOnlyBuffer_Flip(actual);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0,
+ "Expected position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10,
+ "Expected limit to be 10.");
+
+ parcReadOnlyBuffer_Release(&actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Copy)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected);
+
+ PARCReadOnlyBuffer *original = parcReadOnlyBuffer_Create(buffer);
+
+ PARCReadOnlyBuffer *copy = parcReadOnlyBuffer_Copy(original);
+
+ assertTrue(parcReadOnlyBuffer_Equals(original, copy), "Expected the copy to be equal to the original.");
+
+ parcReadOnlyBuffer_Release(&copy);
+ parcReadOnlyBuffer_Release(&original);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Clear)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 10, "Expected position to be 10.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected limit to be 10.");
+
+ parcReadOnlyBuffer_Clear(actual);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected limit to be 10.");
+
+ parcBuffer_Release(&buffer);
+ parcReadOnlyBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_ArrayOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ size_t expected = 5;
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, expected, 10);
+
+ size_t actual = parcReadOnlyBuffer_ArrayOffset(buffer);
+ parcReadOnlyBuffer_Release(&buffer);
+
+ assertTrue(0 == actual,
+ "Expected offset to be 0, actual %zu", actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Position)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 5;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+
+ assertTrue(expected == actual,
+ "Expected position to be 0, actual %zu", actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Overlay)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t expected[5] = { 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t position = 5;
+ parcReadOnlyBuffer_SetPosition(buffer, position);
+ uint8_t *actual = parcReadOnlyBuffer_Overlay(buffer, sizeof(array) - position);
+
+ assertTrue(memcmp(expected, actual, sizeof(expected)) == 0,
+ "Array contents should not be different.");
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetPosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetLimit(buffer, expected);
+ size_t actual = parcReadOnlyBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit_TruncatePosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ parcReadOnlyBuffer_SetPosition(buffer, 5);
+ parcReadOnlyBuffer_Mark(buffer);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetLimit(buffer, expected);
+ size_t actual = parcReadOnlyBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Remaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 10;
+ size_t actual = parcReadOnlyBuffer_Remaining(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_HasRemaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+ bool actual = parcReadOnlyBuffer_HasRemaining(buffer);
+
+ assertTrue(actual, "Expected true");
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Rewind)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+ parcReadOnlyBuffer_SetPosition(buffer, 4);
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+ assertTrue(actual == 4, "Expected position to be at 4.");
+
+ parcReadOnlyBuffer_Rewind(buffer);
+
+ actual = parcReadOnlyBuffer_Position(buffer);
+ assertTrue(actual == 0, "Expected position to be at 0.");
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Mark)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+ parcReadOnlyBuffer_Mark(buffer);
+ parcReadOnlyBuffer_SetPosition(buffer, 4);
+ parcReadOnlyBuffer_Reset(buffer);
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_GetByte)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ uint8_t actual = parcReadOnlyBuffer_GetUint8(buffer);
+
+ assertTrue(array[0] == actual,
+ "Expected %d, actual %d", array[0], actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_GetArray)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ uint8_t actual[10];
+
+ parcReadOnlyBuffer_GetArray(buffer, actual, sizeof(actual));
+
+ assertTrue(memcmp(array, actual, sizeof(actual)) == 0,
+ "Expected arrays to be equal.");
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_HashCode)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *referenceBuffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ PARCReadOnlyBuffer *buffer1 = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ PARCReadOnlyBuffer *buffer2 = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ uint32_t hashX = parcReadOnlyBuffer_HashCode(buffer1);
+ uint32_t hashY = parcReadOnlyBuffer_HashCode(buffer2);
+ uint32_t referenceHash = parcBuffer_HashCode(referenceBuffer);
+
+ assertTrue(hashX == hashY, "Expected %u, actual %u", hashX, hashY);
+ assertTrue(hashX == referenceHash, "Expected %u, actual %u", hashX, hashY);
+
+ parcReadOnlyBuffer_Release(&buffer2);
+ parcReadOnlyBuffer_Release(&buffer1);
+ parcBuffer_Release(&referenceBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_ToString)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ char *actual = parcReadOnlyBuffer_ToString(buffer);
+
+ assertTrue(strcmp("hello worldx", actual) == 0, "Expected 'hello world', actual %s", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Display)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ parcReadOnlyBuffer_Display(buffer, 0);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(Getters)
+{
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint8);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint16);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint32);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint64);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetAtIndex);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Getters)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(100);
+
+ longBowTestCase_SetClipBoardData(testCase, buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Getters)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&buffer);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetAtIndex)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint8_t));
+ uint8_t expected = 0x12;
+
+ parcBuffer_PutUint8(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint8_t actual = parcReadOnlyBuffer_GetAtIndex(readOnly, 0);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint8)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint8_t));
+ uint8_t expected = 0x12;
+
+ parcBuffer_PutUint8(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint8_t actual = parcReadOnlyBuffer_GetUint8(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint16)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t));
+ uint16_t expected = 0x1234;
+
+ parcBuffer_PutUint16(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint16_t actual = parcReadOnlyBuffer_GetUint16(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint32)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint32_t));
+ uint32_t expected = 0x12345678;
+
+ parcBuffer_PutUint32(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint32_t actual = parcReadOnlyBuffer_GetUint32(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint64)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint64_t));
+ uint64_t expected = 0x1234567812345678;
+
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint64_t actual = parcReadOnlyBuffer_GetUint64(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %" PRIu64 ", actual %" PRIu64 "", expected, actual);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcReadOnlyBuffer_GetByte_Underflow);
+ LONGBOW_RUN_TEST_CASE(Errors, parcReadOnlyBuffer_Mark_mark_exceeds_position);
+}
+
+typedef struct parc_buffer_longbow_clipboard {
+ PARCReadOnlyBuffer *buffer;
+} parcReadOnlyBuffer_LongBowClipBoard;
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ parcReadOnlyBuffer_LongBowClipBoard *testData = calloc(1, sizeof(parcReadOnlyBuffer_LongBowClipBoard));
+ testData->buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ longBowTestCase_SetClipBoardData(testCase, testData);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ parcReadOnlyBuffer_Release(&testData->buffer);
+ free(testData);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcReadOnlyBuffer_GetByte_Underflow, .event = &LongBowTrapOutOfBounds)
+{
+ parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCReadOnlyBuffer *buffer = testData->buffer;
+
+ parcReadOnlyBuffer_SetPosition(buffer, 10);
+ parcReadOnlyBuffer_GetUint8(buffer); // this will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcReadOnlyBuffer_Mark_mark_exceeds_position, .event = &LongBowAssertEvent)
+{
+ parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCReadOnlyBuffer *buffer = testData->buffer;
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+ parcReadOnlyBuffer_Mark(buffer);
+ parcReadOnlyBuffer_SetPosition(buffer, 0);
+ parcReadOnlyBuffer_Reset(buffer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ReadableBuffer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_SafeMemory.c b/libparc/parc/algol/test/test_parc_SafeMemory.c
new file mode 100644
index 00000000..53c0b3c8
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_SafeMemory.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_SafeMemory.c"
+
+#include <LongBow/unit-test.h>
+
+#include <fcntl.h>
+
+LONGBOW_TEST_RUNNER(safetyMemory)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(ReportAllocation);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(safetyMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(safetyMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, PARCSafeMemory_Report);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_StateToString);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_FormatPrefix);
+ LONGBOW_RUN_TEST_CASE(Static, _computeUsableMemoryLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, PARCSafeMemory_Report)
+{
+ size_t expectedSize = 100;
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ int fd = open("/dev/null", O_WRONLY);
+ _parcSafeMemory_Report(memory, fd);
+ close(fd);
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_StateToString)
+{
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OK),
+ "PARCSafeMemoryState_OK cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_MISMATCHED),
+ "PARCSafeMemoryState_MISMATCHED cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_UNDERRUN),
+ "PARCSafeMemoryState_UNDERRUN cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OVERRUN),
+ "PARCSafeMemoryState_OVERRUN cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_NOTHINGALLOCATED),
+ "PARCSafeMemoryState_NOTHINGALLOCATED cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_ALREADYFREE),
+ "PARCSafeMemoryState_ALREADYFREE cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(-1),
+ "Garbage cannot be represented by a NULL string.");
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char origin[100]; // just some number
+
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) origin, expectedLength, expectedAlignment);
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory);
+ assertTrue(actual == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemoryState_OK, actual = %d", actual);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE)
+{
+ PARCSafeMemoryUsable *usable = parcSafeMemory_Allocate(10);
+ PARCSafeMemoryUsable *saved = usable;
+
+ parcSafeMemory_Deallocate((void **) &usable);
+
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(saved);
+ assertTrue(actual == PARCSafeMemoryState_ALREADYFREE,
+ "Expected PARCSafeMemoryState_ALREADYFREE, actual = %d", actual);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN)
+{
+ char *usable = parcSafeMemory_Allocate(10);
+
+ char savedByte = usable[-1];
+ usable[-1] = 0;
+
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState((PARCSafeMemoryUsable *) usable);
+ assertTrue(actual == PARCSafeMemoryState_UNDERRUN,
+ "Expected PARCSafeMemoryState_UNDERRUN, actual = %d", actual);
+ usable[-1] = savedByte;
+ parcSafeMemory_Deallocate((void **) &usable);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_FormatPrefix)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *) - 1;
+ char base[100]; // just some number
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ assertNull(memory,
+ "Expected _parcSafeMemory_FormatPrefix to return NULL for bad alignment specification.");
+}
+
+LONGBOW_TEST_CASE(Static, _computeUsableMemoryLength)
+{
+ size_t actual = _computeUsableMemoryLength(100, sizeof(void *));
+
+ // The result must be >= to the requested length and an even multiple of sizeof(void *)
+ assertTrue(actual >= 100 && (actual % sizeof(void *)) == 0,
+ "Expected the result to be >= to the requested length and an even multiple of sizeof(void *)");
+}
+
+LONGBOW_TEST_FIXTURE(ReportAllocation)
+{
+ LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty);
+ LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One);
+ LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated);
+}
+
+LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty)
+{
+ _parcSafeMemory_DeallocateAll();
+ int fd = open("/dev/null", O_WRONLY);
+ size_t result = parcSafeMemory_ReportAllocation(fd);
+ close(fd);
+ assertTrue(result == 0, "Expected 0, was %zd", result);
+}
+
+LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+
+ int fd = open("/dev/null", O_WRONLY);
+ size_t result = parcSafeMemory_ReportAllocation(fd);
+ close(fd);
+ assertTrue(result == 1, "Expected 1, was %zd", result);
+
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated)
+{
+ size_t size = 100;
+ void *memory = parcSafeMemory_Allocate(size);
+ assertTrue(parcSafeMemory_Outstanding() != 0, "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+ assertTrue(state == PARCSafeMemoryState_OK, "Expected uncorrupted memory.");
+
+ int fd = open("/dev/null", O_WRONLY);
+ size_t result = parcSafeMemory_ReportAllocation(fd);
+ close(fd);
+
+ assertTrue(result == 0, "Expected 0, was %zd", result);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ReportAllocation)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ReportAllocation)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_MemAlign);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger);
+ LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero);
+ LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Validate);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_AllocateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display_NULL);
+
+ LONGBOW_RUN_TEST_CASE(Global, compute_prefix_length);
+ LONGBOW_RUN_TEST_CASE(Global, _parcSafeMemory_FormatMemory);
+ LONGBOW_RUN_TEST_CASE(Global, memory_prefix_format);
+ LONGBOW_RUN_TEST_CASE(Global, memory_prefix_validate);
+ LONGBOW_RUN_TEST_CASE(Global, memory_suffix_format);
+ LONGBOW_RUN_TEST_CASE(Global, memory_suffix_validate);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short);
+ LONGBOW_RUN_TEST_CASE(Global, validateAlignment);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ assertTrue(parcSafeMemory_Outstanding() == 0, "Expected 0 outstanding allocations")
+ {
+ printf("Leaking test case: %s", longBowTestCase_GetName(testCase));
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(Global, validateAlignment)
+{
+ assertTrue(_alignmentIsValid(sizeof(void *)),
+ "Expected alignment of sizeof(void *) failed.");
+ assertTrue(_alignmentIsValid(16),
+ "Expected alignment of 16 failed.");
+}
+
+LONGBOW_TEST_CASE(Global, compute_prefix_length)
+{
+ // Test that the result is a multiple of the alignment value and greater than the size of _MemoryPrefix.
+ for (int i = 0; i < 9; i++) {
+ size_t alignment = 1 << i;
+ size_t actual = _computePrefixLength(alignment);
+ assertTrue((actual & (alignment - 1)) == 0,
+ "Alignment needs to be a multiple of %zd", alignment);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, memory_prefix_format)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ assertAligned(prefix, sizeof(void *),
+ "prefix address %p is not aligned to %d",
+ memory, expectedAlignment);
+ assertAligned(memory, expectedAlignment,
+ "memory address %p is not aligned to %d",
+ memory, expectedAlignment);
+
+ assertTrue((void *) prefix >= (void *) base,
+ "Expected >= %p, actual %p", (void *) base, (void *) prefix);
+ assertTrue(_parcSafeMemory_PrefixMagic == prefix->magic,
+ "Prefix magic is wrong.");
+ assertTrue(expectedLength == prefix->requestedLength,
+ "Expected length %zd, actual %zd", expectedLength, prefix->requestedLength);
+ assertTrue(expectedAlignment == prefix->alignment,
+ "Expected alignment %d, actual %zu",
+ expectedAlignment, prefix->alignment);
+ assertTrue(_parcSafeMemory_Guard == prefix->guard,
+ "Prefix guard is wrong.");
+}
+
+LONGBOW_TEST_CASE(Global, memory_suffix_format)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory);
+ assertAligned(suffix, sizeof(void *), "suffix pointer is not aligned to %zu", sizeof(void*));
+}
+
+LONGBOW_TEST_CASE(Global, memory_suffix_validate)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory);
+ assertAligned(suffix, sizeof(void *),
+ "suffix pointer is not aligned to %zu", sizeof(void*));
+
+ PARCSafeMemoryState suffixState = _parcSafeMemory_GetSuffixState(memory);
+ assertTrue(suffixState == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemoryState_OK suffix state, actual %s", _parcSafeMemory_StateToString(suffixState));
+}
+
+LONGBOW_TEST_CASE(Global, memory_prefix_validate)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory);
+ assertTrue(actual == PARCSafeMemoryState_OK,
+ "Expected valid prefix, actual = %d", actual);
+}
+
+LONGBOW_TEST_CASE(Global, _parcSafeMemory_FormatMemory)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+
+ void *memory = _parcSafeMemory_FormatMemory((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Memory did not validate. Actual %d", state);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+
+ assertTrue(memory != NULL,
+ "Expected non-NULL return.");
+
+ assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK,
+ "Prefix did not validate.");
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_MemAlign)
+{
+ void *memory;
+ size_t size = 100;
+
+ int failure = parcSafeMemory_MemAlign(&memory, sizeof(void *), size);
+ assertTrue(failure == 0,
+ "parcSafeMemory_MemAlign failed: %d", failure);
+
+ assertTrue(memory != NULL,
+ "Expected non-NULL return.");
+
+ assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK,
+ "Prefix did not validate.");
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_ReportAllocation)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+ assertTrue(memory != NULL, "Expected non-NULL return.");
+ PARCSafeMemoryState prefixState = _parcSafeMemory_GetPrefixState(memory);
+ assertTrue(prefixState == PARCSafeMemoryState_OK,
+ "Prefix did not validate.");
+
+ parcSafeMemory_ReportAllocation(1);
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_Validate)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger)
+{
+ void *memory = parcSafeMemory_Allocate(100);
+
+ for (unsigned char i = 0; i < 100; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Expected memory to be OK.");
+
+ size_t expectedLength = 100 + 1;
+ unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength);
+
+ assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) memory) != PARCSafeMemoryState_OK,
+ "Expected original memory to NOT be OK.");
+ assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK,
+ "Expected new memory to be OK.");
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory);
+ assertTrue(prefix->requestedLength == expectedLength,
+ "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength);
+
+ for (int i = 0; i < 100; i++) {
+ assertTrue(((unsigned char *) newMemory)[i] == i,
+ "PARCSafeMemory_Realloc did not copy old memory correctly");
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory);
+ parcSafeMemory_Deallocate((void **) &newMemory);
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state);
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected old memory to be invalid.");
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller)
+{
+ void *memory = parcSafeMemory_Allocate(100);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < 100; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ size_t expectedLength = 100 - 1;
+ unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength);
+
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected original memory to NOT be OK.");
+ assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK,
+ "Expected new memory to be OK.");
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory);
+ assertTrue(prefix->requestedLength == expectedLength,
+ "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength);
+
+ for (int i = 0; i < expectedLength; i++) {
+ assertTrue(((unsigned char *) newMemory)[i] == i,
+ "PARCSafeMemory_Realloc did not copy correctly");
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory);
+ parcSafeMemory_Deallocate((void **) &newMemory);
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state);
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected old memory to be invalid.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero)
+{
+ void *memory = parcSafeMemory_Allocate(100);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < 100; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ size_t expectedLength = 0;
+ unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength);
+
+ assertTrue(newMemory == NULL,
+ "Expected NULL, actual %p", (void *) newMemory);
+
+ parcSafeMemory_Deallocate(&memory);
+ assertNull(memory,
+ "Expected memory pointer to be NULL.");
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_DoubleFree)
+{
+ size_t expectedSize = 100;
+
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < expectedSize; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Expected memory to validate");
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+ assertTrue(state == PARCSafeMemoryState_UNDERRUN,
+ "Expected memory to be underrun (double free).");
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate)
+{
+ char *string = "hello world";
+ char *actual = parcSafeMemory_StringDuplicate(string, strlen(string));
+
+ assertTrue(strcmp(string, actual) == 0,
+ "Expected %s, actual %s", string, actual);
+ parcSafeMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long)
+{
+ char *string = "hello world";
+ char *actual = parcSafeMemory_StringDuplicate(string, SIZE_MAX);
+
+ assertTrue(strcmp(string, actual) == 0,
+ "Expected %s, actual %s", string, actual);
+ parcSafeMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short)
+{
+ char *string = "hello world";
+ char *expected = "hello";
+ char *actual = parcSafeMemory_StringDuplicate(string, 5);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcSafeMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment)
+{
+ void *result;
+ size_t alignment = 3;
+ size_t size = 100;
+
+ int failure = parcSafeMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcSafeMemory_MemAlign failed to report bad aligment specification");
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize)
+{
+ void *result;
+ size_t alignment = sizeof(void *);
+ size_t size = 0;
+
+ int failure = parcSafeMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcSafeMemory_MemAlign failed to report bad aligment specification");
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_AllocateAndClear)
+{
+ void *result;
+ size_t size = 100;
+
+ result = parcSafeMemory_AllocateAndClear(size);
+ assertNotNull(result,
+ "parcSafeMemory_AllocateAndClear failed: NULL result.");
+
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(((char *) result)[i] == 0,
+ "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i);
+ }
+ assertTrue(parcSafeMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+ parcSafeMemory_Deallocate(&result);
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate)
+{
+ size_t size = 100;
+
+ void *result = parcSafeMemory_AllocateAndClear(size);
+ assertNotNull(result,
+ "parcSafeMemory_Allocate failed: NULL.");
+
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(((char *) result)[i] == 0,
+ "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i);
+ }
+
+ result = parcSafeMemory_Reallocate(result, size * 2);
+
+ assertTrue(parcSafeMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+ parcSafeMemory_Deallocate(&result);
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated)
+{
+ void *result = 0;
+
+ parcSafeMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_True)
+{
+ void *result = parcSafeMemory_AllocateAndClear(5);
+
+ assertTrue(parcSafeMemory_IsValid(result), "Expected properly allocated memory to be valid PARC Safe Memory.");
+
+ parcSafeMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_False)
+{
+ char *memory[10];
+
+ assertFalse(parcSafeMemory_IsValid(memory), "Expected improperly allocated memory to be invalid PARC Safe Memory.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Display)
+{
+ void *result = parcSafeMemory_AllocateAndClear(5);
+
+ parcSafeMemory_Display(result, 0);
+ parcSafeMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Display_NULL)
+{
+ parcSafeMemory_Display(NULL, 0);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL);
+ LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Underrun);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ // The tests purposefully wreck the various per-allocation accounting structures for the allocated memory in order to test for
+ // properly catching the overrun, underrun or other damage.
+ // As a result any cleanup of allocated memory is not possible, so these tests leak allocated memory.
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL)
+{
+ void *result = NULL;
+ size_t size = 100;
+
+ result = parcSafeMemory_Reallocate(result, size * 2);
+
+ assertTrue(parcSafeMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+ parcSafeMemory_Deallocate(&result);
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Underrun, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ size_t expectedSize = sizeof(void *) * 2;
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (int i = -2; i < (int) expectedSize; i++) {
+ ((unsigned char *) memory)[i] = (unsigned char) i;
+ }
+
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_UNDERRUN,
+ "Memory did not underrun.");
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+
+ assertTrue(state == PARCSafeMemoryState_UNDERRUN,
+ "Expected memory to be underrun");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Overrun, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ size_t expectedSize = 100;
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < expectedSize + 5; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected not OK, actual %s", _parcSafeMemory_StateToString(_parcSafeMemory_GetState(memory)));
+ // this is expected to fail
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase);
+ LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase);
+
+ LONGBOW_RUN_TEST_CASE(Performance, _computeUsableMemoryLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *memory[1000000];
+
+LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase)
+{
+ size_t size = 100;
+
+ for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) {
+ memory[i] = parcSafeMemory_Allocate(size);
+ }
+ for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) {
+ parcSafeMemory_Deallocate(&memory[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase)
+{
+ size_t size = 100;
+
+ for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) {
+ memory[i] = parcSafeMemory_Allocate(size);
+ }
+
+ int i = sizeof(memory) / sizeof(memory[0]);
+ do {
+ i--;
+ parcSafeMemory_Deallocate(&memory[i]);
+ } while (i > 0);
+}
+
+LONGBOW_TEST_CASE(Performance, _computeUsableMemoryLength)
+{
+ for (int i = 0; i < 100000000; i++) {
+ size_t alignment = sizeof(void *);
+ size_t requestedLength = 10;
+ _computeUsableMemoryLength(requestedLength, alignment);
+ }
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(safetyMemory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_SortedList.c b/libparc/parc/algol/test/test_parc_SortedList.c
new file mode 100644
index 00000000..f0445d86
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_SortedList.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_SortedList.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_SortedList)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_SortedList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SortedList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCompare);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ assertNotNull(instance, "Expected non-null result from parcSortedList_Create();");
+
+ parcObjectTesting_AssertAcquire(instance);
+
+ parcSortedList_Release(&instance);
+ assertNull(instance, "Expected null result from parcSortedList_Release();");
+}
+
+// A signum function to compare two PARCBuffers by length of buffer.
+static int
+_compareTwoBuffersByLength(const PARCObject *buf1, const PARCObject *buf2)
+{
+ size_t size1 = parcBuffer_Limit((PARCBuffer *) buf1);
+ size_t size2 = parcBuffer_Limit((PARCBuffer *) buf2);
+
+ if (size1 > size2) {
+ return 1;
+ } else if (size2 > size1) {
+ return -1;
+ }
+ return 0;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCompare)
+{
+ PARCSortedList *instance = parcSortedList_CreateCompare(_compareTwoBuffersByLength);
+
+ PARCBuffer *buf1 = parcBuffer_WrapCString("medium long");
+ PARCBuffer *buf2 = parcBuffer_WrapCString("somewhat longer");
+ PARCBuffer *buf3 = parcBuffer_WrapCString("short");
+
+ parcSortedList_Add(instance, buf1);
+ parcSortedList_Add(instance, buf2);
+ parcSortedList_Add(instance, buf3);
+
+ PARCBuffer *test = parcSortedList_GetAtIndex(instance, 0);
+ assertTrue(test == buf3, "Expected the shortes buffer first");
+
+ test = parcSortedList_GetAtIndex(instance, 1);
+ assertTrue(test == buf1, "Expected the medium length buffer second");
+
+ test = parcSortedList_GetAtIndex(instance, 2);
+ assertTrue(test == buf2, "Expected the longest buffer last");
+
+ parcBuffer_Release(&buf1);
+ parcBuffer_Release(&buf2);
+ parcBuffer_Release(&buf3);
+
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_Copy)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCSortedList *copy = parcSortedList_Copy(instance);
+ assertTrue(parcSortedList_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcSortedList_Release(&instance);
+ parcSortedList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_Display)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_Equals)
+{
+ PARCSortedList *x = parcSortedList_Create();
+ PARCSortedList *y = parcSortedList_Create();
+ PARCSortedList *z = parcSortedList_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcSortedList_Release(&x);
+ parcSortedList_Release(&y);
+ parcSortedList_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_HashCode)
+{
+ PARCSortedList *x = parcSortedList_Create();
+ PARCSortedList *y = parcSortedList_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcSortedList_Release(&x);
+ parcSortedList_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_IsValid)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ assertTrue(parcSortedList_IsValid(instance), "Expected parcSortedList_Create to result in a valid instance.");
+
+ parcSortedList_Release(&instance);
+ assertFalse(parcSortedList_IsValid(instance), "Expected parcSortedList_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_ToJSON)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+
+ PARCJSON *json = parcSortedList_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_ToString)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+
+ char *string = parcSortedList_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcSortedList_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_Add);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_Remove);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetAtIndex);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetFirst);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetLast);
+
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveFirst);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveFirst_SingleElement);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveLast);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+dump(PARCSortedList *i)
+{
+ PARCIterator *iterator = parcSortedList_CreateIterator(i);
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = parcIterator_Next(iterator);
+ parcBuffer_Display(buffer, 0);
+ }
+
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_Add)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element8);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element3);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element4);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element7);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element6);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element5);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element6);
+ parcSortedList_Display(instance, 0);
+
+ dump(instance);
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_Remove)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+ parcSortedList_Display(instance, 0);
+
+ parcSortedList_Remove(instance, element2);
+
+ assertTrue(parcSortedList_Size(instance) == 2, "Expected list to be 2 in size");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_GetAtIndex)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+
+ PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetAtIndex(instance, 1);
+ assertTrue(parcBuffer_Equals(element2, actual), "Got the wrong value at index 1");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_GetFirst)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+
+ PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetFirst(instance);
+ assertTrue(parcBuffer_Equals(element1, actual), "Got the wrong value.");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_GetLast)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+
+ PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetLast(instance);
+ assertTrue(parcBuffer_Equals(element3, actual), "Got the wrong value at index 1");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveFirst)
+{
+ PARCSortedList *deque = parcSortedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ parcSortedList_Add(deque, object1);
+ parcSortedList_Add(deque, object2);
+ parcSortedList_Add(deque, object3);
+
+ PARCBuffer *peek = parcSortedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek), "Objects out of order");
+
+ parcBuffer_Release(&peek);
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcSortedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveFirst_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCSortedList *deque = parcSortedList_Create();
+ parcSortedList_Add(deque, object1);
+
+ PARCBuffer *peek = parcSortedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcBuffer_Release(&object1);
+ parcSortedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveLast)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCSortedList *deque = parcSortedList_Create();
+ parcSortedList_Add(deque, object1);
+ parcSortedList_Add(deque, object2);
+ parcSortedList_Add(deque, object3);
+
+ PARCBuffer *peek = parcSortedList_RemoveLast(deque);
+ assertTrue(parcBuffer_Equals(object3, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcSortedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveLast_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ PARCSortedList *deque = parcSortedList_Create();
+ parcSortedList_Add(deque, object1);
+
+ PARCBuffer *peek = parcSortedList_RemoveLast(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&object1);
+ parcSortedList_Release(&deque);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SortedList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Stack.c b/libparc/parc/algol/test/test_parc_Stack.c
new file mode 100755
index 00000000..3ca27682
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Stack.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+#include "../parc_Stack.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(test_parc_Stack)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_Stack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Stack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcStack_IsEmpty_PARCDeque);
+ LONGBOW_RUN_TEST_CASE(Global, parcStack_IsEmpty_PARCArrayList);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcStack_IsEmpty_PARCDeque)
+{
+ PARCStackInterface dequeAsStack = {
+ .parcStack_Release = (void (*)(void **))parcDeque_Release,
+ .parcStack_IsEmpty = (bool (*)(const void *))parcDeque_IsEmpty,
+ .parcStack_Peek = (void *(*)(const void *))parcDeque_PeekLast,
+ .parcStack_Pop = (void *(*)(void *))parcDeque_RemoveLast,
+ .parcStack_Push = (void *(*)(void *, void *))parcDeque_Append,
+ .parcStack_Search = NULL
+ };
+
+ PARCStack *stack = parcStack(parcDeque_Create(), &dequeAsStack);
+
+ bool actual = parcStack_IsEmpty(stack);
+ parcStack_Release(&stack);
+ assertTrue(actual, "Expected the stack to be empty.");
+}
+
+LONGBOW_TEST_CASE(Global, parcStack_IsEmpty_PARCArrayList)
+{
+ PARCStackInterface arrayListAsStack = {
+ .parcStack_Release = (void (*)(void **))parcArrayList_Destroy,
+ .parcStack_IsEmpty = (bool (*)(const void *))parcArrayList_IsEmpty,
+ .parcStack_Peek = (void *(*)(const void *))parcArrayList_Peek,
+ .parcStack_Pop = (void *(*)(void *))parcArrayList_Pop,
+ .parcStack_Push = (void *(*)(void *, void *))parcArrayList_Add,
+ .parcStack_Search = NULL
+ };
+
+ PARCStack *stack = parcStack(parcArrayList_Create(NULL), &arrayListAsStack);
+
+ bool actual = parcStack_IsEmpty(stack);
+ parcStack_Release(&stack);
+ assertTrue(actual, "Expected the stack to be empty.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Stack);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_StdlibMemory.c b/libparc/parc/algol/test/test_parc_StdlibMemory.c
new file mode 100644
index 00000000..7cf49991
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_StdlibMemory.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** *
+ */
+#include "../parc_StdlibMemory.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(test_parc_StdlibMemory)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Threads);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_StdlibMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_StdlibMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadAlignment);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear_BadSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Reallocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Reallocate_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_StringDuplicate);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaks allocations.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_Allocate)
+{
+ size_t size = 100;
+
+ void *result = parcStdlibMemory_Allocate(size);
+
+ assertNotNull(result, "parcStdlibMemory_Allocate failed: NULL result.");
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadAlignment)
+{
+ void *result;
+ size_t alignment = 3;
+ size_t size = 1200;
+
+ int failure = parcStdlibMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcStdlibMemory_Allocate failed to report bad aligment specification");
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadSize)
+{
+ void *result;
+ size_t alignment = sizeof(void *);
+ size_t size = 0;
+
+ int failure = parcStdlibMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcStdlibMemory_Allocate failed to report bad aligment specification");
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear)
+{
+ size_t size = 1200;
+
+ void *result = parcStdlibMemory_AllocateAndClear(size);
+ assertNotNull(result, "parcStdlibMemory_Allocate failed: NULL result.");
+
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(((char *) result)[i] == 0,
+ "parcStdlibMemory_AllocateAndClear failed to zero memory at index %zd", i);
+ }
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear_BadSize)
+{
+ void *result;
+ size_t alignment = sizeof(void *);
+ size_t size = 0;
+
+ int failure = parcStdlibMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcStdlibMemory_Allocate failed to report bad aligment specification");
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+static void
+_test_SetMemory(unsigned char *memory, size_t size)
+{
+ for (size_t i = 0; i < size; i++) {
+ memory[i] = i;
+ }
+}
+
+static void
+_test_CheckMemory(unsigned char *memory, size_t size)
+{
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(memory[i] == (i % 256), "memory failed to check at index %zd", i);
+ }
+}
+
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_Reallocate)
+{
+ size_t size = 1200;
+
+ void *result = parcStdlibMemory_AllocateAndClear(size);
+ assertNotNull(result,
+ "parcStdlibMemory_Allocate failed: NULL result.");
+
+ _test_SetMemory(result, size);
+ _test_CheckMemory(result, size);
+
+ result = parcStdlibMemory_Reallocate(result, size * 2);
+
+ _test_CheckMemory(result, size);
+
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_Reallocate_NULL)
+{
+ void *result = NULL;
+ size_t size = 1200;
+
+ result = parcStdlibMemory_Reallocate(result, size * 2);
+ _test_SetMemory(result, size * 2);
+ _test_CheckMemory(result, size * 2);
+
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_StringDuplicate)
+{
+ char *expected = "Hello World";
+ char *actual = parcStdlibMemory_StringDuplicate(expected, strlen(expected));
+
+ assertTrue(expected != actual,
+ "Expected a distinct pointer unequal to the original string");
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected strings to be equal. '%s' vs '%s'", expected, actual);
+
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate((void **) &actual);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_FIXTURE(Threads)
+{
+ LONGBOW_RUN_TEST_CASE(Threads, Threads1000);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Threads)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Threads)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *
+allocator(void *unused)
+{
+ for (int i = 0; i < 1000; i++) {
+ void *memory = parcStdlibMemory_Allocate(10);
+ parcStdlibMemory_Deallocate(&memory);
+ }
+ return 0;
+}
+
+LONGBOW_TEST_CASE(Threads, Threads1000)
+{
+#define NTHREADS 1000
+ pthread_t thread[NTHREADS];
+
+ for (int i = 0; i < NTHREADS; i++) {
+ pthread_create(&thread[i], NULL, allocator, NULL);
+ }
+ for (int i = 0; i < NTHREADS; i++) {
+ pthread_join(thread[0], NULL);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Forward);
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Reverse);
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Forward);
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Reverse);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+#define ELEMENT_COUNT 1000000
+#define ELEMENT_SIZE 151
+void *memory[ELEMENT_COUNT];
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Forward)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ memory[i] = parcStdlibMemory_Allocate(ELEMENT_SIZE);
+ }
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_Deallocate(&memory[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Reverse)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ memory[i] = parcStdlibMemory_Allocate(ELEMENT_SIZE);
+ }
+
+ int i = ELEMENT_COUNT;
+ do {
+ i--;
+ parcStdlibMemory_Deallocate(&memory[i]);
+ } while (i > 0);
+}
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Forward)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_MemAlign(&memory[i], sizeof(void *), ELEMENT_SIZE);
+ }
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_Deallocate(&memory[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Reverse)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_MemAlign(&memory[i], sizeof(void *), ELEMENT_SIZE);
+ }
+
+ int i = ELEMENT_COUNT;
+ do {
+ i--;
+ parcStdlibMemory_Deallocate(&memory[i]);
+ } while (i > 0);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_StdlibMemory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_String.c b/libparc/parc/algol/test/test_parc_String.c
new file mode 100644
index 00000000..84d3d3da
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_String.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_String.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_String)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_String)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_String)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ assertNotNull(instance, "Expected non-null result from parcString_Create();");
+ parcObjectTesting_AssertAcquireReleaseImpl(instance);
+
+ parcString_Release(&instance);
+ assertNull(instance, "Expected null result from parcString_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Compare)
+{
+ PARCString *string = parcString_Create("Hello1");
+ PARCString *equivalent[2] = {
+ parcString_Create("Hello1"),
+ NULL
+ };
+ PARCString *greater[2] = {
+ parcString_Create("Hello2"),
+ NULL
+ };
+ PARCString *lesser[2] = {
+ parcString_Create("Hello0"),
+ NULL
+ };
+
+ parcObjectTesting_AssertCompareTo(parcString_Compare, string, equivalent, lesser, greater);
+ parcString_Release(&string);
+ parcString_Release(&equivalent[0]);
+ parcString_Release(&greater[0]);
+ parcString_Release(&lesser[0]);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Copy)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ PARCString *copy = parcString_Copy(instance);
+ assertTrue(parcString_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcString_Release(&instance);
+ parcString_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Display)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ parcString_Display(instance, 0);
+ parcString_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Equals)
+{
+ PARCString *x = parcString_Create("Hello World");
+ PARCString *y = parcString_Create("Hello World");
+ PARCString *z = parcString_Create("Hello World");
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcString_Release(&x);
+ parcString_Release(&y);
+ parcString_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_HashCode)
+{
+ PARCString *x = parcString_Create("Hello World");
+ PARCString *y = parcString_Create("Hello World");
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcString_Release(&x);
+ parcString_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_IsValid)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ assertTrue(parcString_IsValid(instance), "Expected parcString_Create to result in a valid instance.");
+
+ parcString_Release(&instance);
+ assertFalse(parcString_IsValid(instance), "Expected parcString_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcString_ToJSON)
+{
+ PARCString *instance = parcString_Create("Hello World");
+
+ PARCJSON *json = parcString_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcString_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_ToString)
+{
+ PARCString *instance = parcString_Create("Hello World");
+
+ char *string = parcString_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcString_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcString_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_String);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/algol/test/test_parc_Time.c b/libparc/parc/algol/test/test_parc_Time.c
new file mode 100644
index 00000000..2befdde1
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Time.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Time.c"
+
+LONGBOW_TEST_RUNNER(test_parc_Time)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_Time)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Time)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsString);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsISO8601);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsRFC3339);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_RFC3339_Now);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_NowTimeval);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_NowMicroseconds);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_TimevalAsString)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "0.001000";
+ char *actual = parcTime_TimevalAsString(timeval);
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_TimevalAsISO8601)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "1970-01-01 00:00:00.001000Z";
+
+ char actual[64];
+ parcTime_TimevalAsISO8601(&timeval, actual);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_TimevalAsRFC3339)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "1970-01-01T00:00:00.001000Z";
+
+ char actual[64];
+ parcTime_TimevalAsRFC3339(&timeval, actual);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_RFC3339_Now)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ char actual[64];
+ parcTime_TimevalAsRFC3339(&timeval, actual);
+ printf("%s\n", actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_NowTimeval)
+{
+ struct timeval result = parcTime_NowTimeval();
+ assertTrue(result.tv_sec != 0, "Expected NOW to not be zero.");
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_NowMicroseconds)
+{
+ uint64_t result = parcTime_NowMicroseconds();
+ assertTrue(result != 0, "Expected NOW to not be zero.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Time);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_TreeMap.c b/libparc/parc/algol/test/test_parc_TreeMap.c
new file mode 100755
index 00000000..9355380b
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_TreeMap.c
@@ -0,0 +1,1565 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_TreeMap.c"
+
+
+typedef struct {
+ int value;
+} _Int;
+
+static _Int *
+_int_Copy(const _Int *source);
+
+static bool
+_int_Equals(const _Int *a, const _Int *b)
+{
+ return a->value == b->value;
+}
+
+static int
+_int_Compare(const _Int *a, const _Int *b)
+{
+ int result = 0;
+ if (a->value > b->value) {
+ result = 1;
+ } else if (a->value < b->value) {
+ result = -1;
+ }
+
+ return result;
+}
+
+parcObject_ExtendPARCObject(_Int, NULL, _int_Copy, NULL, _int_Equals, _int_Compare, NULL, NULL);
+
+static
+parcObject_ImplementRelease(_int, _Int);
+
+static _Int *
+_int_Create(const int value)
+{
+ _Int *newObj = parcObject_CreateInstance(_Int);
+ assertNotNull(newObj, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ newObj->value = value;
+ return newObj;
+}
+
+static _Int *
+_int_Copy(const _Int *source)
+{
+ return _int_Create(source->value);
+}
+
+static _Int *
+_int_Set(_Int *obj, const int value)
+{
+ obj->value = value;
+ return obj;
+}
+static PARCBuffer*
+strBuf(char *key)
+{
+ return parcBuffer_WrapCString(key);
+}
+
+
+LONGBOW_TEST_RUNNER(PARC_TreeMap)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Stress);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_TreeMap)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ int seed = (int) time(NULL);
+ srandom(seed);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_TreeMap)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Create);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Release);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_OutOfOrder);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_ReleaseTillEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_EmptyTree);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Biggest);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Smallest);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstKey_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastKey_Empty);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LowerEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LowerKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_HigherEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_HigherKey);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_WithSuccessorNonRoot);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_LeftChildRightChild);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_DifferentLength);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Copy_Direct);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Iterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_ValueIterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_KeyIterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Using_Iterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Element_Using_Iterator);
+}
+
+#define N_TEST_ELEMENTS 42
+
+typedef struct {
+ PARCTreeMap *testMap1;
+ PARCTreeMap *testMap2;
+ _Int *k[N_TEST_ELEMENTS];
+ _Int *v[N_TEST_ELEMENTS];
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->testMap1 = parcTreeMap_Create();
+ data->testMap2 = parcTreeMap_CreateCustom((PARCTreeMap_CustomCompare *) _int_Compare);
+
+ for (int i = 0; i < N_TEST_ELEMENTS; ++i) {
+ data->k[i] = _int_Create(i);
+ data->v[i] = _int_Create(i + 1000);
+ }
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcTreeMap_Release(&data->testMap1);
+ parcTreeMap_Release(&data->testMap2);
+
+ for (int i = 0; i < N_TEST_ELEMENTS; ++i) {
+ _int_Release(&(data->k[i]));
+ _int_Release(&(data->v[i]));
+ }
+
+ parcMemory_Deallocate((void **) &data);
+
+ /*
+ * uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ * if (outstandingAllocations != 0) {
+ * printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ * return LONGBOW_STATUS_MEMORYLEAK;
+ * }
+ */
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static
+int
+recursiveCheckBlackDepth(const PARCTreeMap *tree, const _RBNode *node)
+{
+ assertNotNull(tree, "Null tree?\n");
+ assertNotNull(node, "Null node?\n");
+ if (node == tree->nil) {
+ return 0;
+ }
+ int right_depth = recursiveCheckBlackDepth(tree, node->rightChild);
+ int left_depth = recursiveCheckBlackDepth(tree, node->leftChild);
+ assertTrue(right_depth == left_depth, "Wrong depth!!\n");
+ if (_rbNodeColor(node) == BLACK) {
+ return right_depth + 1;
+ }
+ return right_depth;
+}
+
+static
+void
+rbCheckTree(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+ if (tree->size > 0) {
+ recursiveCheckBlackDepth(tree, tree->root);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Ordered)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ for (int i = 0; i < 16; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ for (int i = 0; i < 14; i++) {
+ //rbPrintTreeString(tree1);
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[i]);
+ assertNotNull(value, "Data is null!");
+ assertTrue(_int_Equals(value, data->v[i]), "Expect the ordered value.");
+ parcObject_Release(&value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Create)
+{
+ PARCTreeMap *map = parcTreeMap_Create();
+ parcTreeMap_Release(&map);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *map = parcTreeMap_Acquire(data->testMap1);
+ parcTreeMap_Release(&map);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Release)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCBuffer *value1 = strBuf("value 1");
+ PARCBuffer *key1 = strBuf("1");
+ PARCBuffer *value2 = strBuf("value 2");
+ PARCBuffer *key2 = strBuf("2");
+ PARCBuffer *value3 = strBuf("value 3");
+ PARCBuffer *key3 = strBuf("3");
+
+ parcTreeMap_Put(tree, key1, value1);
+ parcTreeMap_Put(tree, key2, value2);
+ parcTreeMap_Put(tree, key3, value3);
+
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Overwrite)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[1], data->v[1]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+ parcTreeMap_Put(tree, data->k[3], data->v[4]);
+ parcTreeMap_Put(tree, data->k[3], data->v[5]);
+
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree should stay at 3");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Ordered)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[1], data->v[1]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_OutOfOrder)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ parcTreeMap_Put(tree1, data->k[4], data->v[4]);
+ parcTreeMap_Put(tree1, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree1, data->k[3], data->v[3]);
+ parcTreeMap_Put(tree1, data->k[1], data->v[1]);
+
+ PARCTreeMap *tree2 = data->testMap2;
+ parcTreeMap_Put(tree2, data->k[1], data->v[1]);
+ parcTreeMap_Put(tree2, data->k[3], data->v[3]);
+ parcTreeMap_Put(tree2, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree2, data->k[4], data->v[4]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Expect trees to be Equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ assertTrue(0 == parcTreeMap_Size(tree), "Wrong size of tree - empty, start");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[4], data->v[4]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after add 3");
+
+ parcTreeMap_Put(tree, data->k[1], data->v[1]);
+
+ assertTrue(4 == parcTreeMap_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeMap_RemoveAndRelease(tree, data->k[2]);
+
+ size_t size = parcTreeMap_Size(tree);
+
+ assertTrue(3 == size, "Wrong size of tree after 1 delete (%zu instead of 3)", size);
+
+ parcTreeMap_Put(tree, data->k[7], data->v[7]);
+
+ assertTrue(4 == parcTreeMap_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeMap_RemoveAndRelease(tree, data->k[3]);
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after del 1 more - 3");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_ReleaseTillEmpty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ // This order of puts are removes exercises code paths
+ // in TreeMap not exercised in any other place.
+ int idx1a[7] = { 4, 2, 3, 1, 5, 7, 6 };
+ int idx1b[7] = { 3, 1, 4, 2, 6, 5, 7 };
+ int idx2a[7] = { 4, 6, 5, 7, 3, 1, 2 };
+ int idx2b[7] = { 5, 7, 4, 6, 2, 3, 1 };
+
+ for (int i = 0; i < 7; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1a[i]], data->v[idx1a[i]]);
+ parcTreeMap_Put(tree2, data->k[idx2a[i]], data->v[idx2a[i]]);
+ }
+
+ for (int i = 0; i < 7; ++i) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[idx1b[i]]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[idx2b[i]]);
+ }
+
+ size_t size;
+ size = parcTreeMap_Size(tree1);
+
+ assertTrue(0 == size, "Wrong size of tree - empty (got %zu)", size);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size_Overwrite)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[4], data->v[4]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+
+ // Size is 3 here, we'll insert the same number now..
+
+ parcTreeMap_Put(tree, data->k[3], data->v[23]);
+
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after overwrite");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_EmptyTree)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[1]);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_NonExistent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[23]);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_First)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 4; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[1]);
+
+ assertTrue(_int_Equals(data->v[1], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[4]);
+
+ assertTrue(_int_Equals(data->v[4], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Last)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[9]);
+
+ assertTrue(_int_Equals(data->v[9], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Smallest)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[1]);
+
+ assertTrue(_int_Equals(data->v[1], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Biggest)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[39]);
+
+ assertTrue(_int_Equals(data->v[39], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCKeyValue *entry = parcTreeMap_GetFirstEntry(tree);
+
+ assertTrue(_int_Equals(data->k[1], parcKeyValue_GetKey(entry)),
+ "Wrong value, got %ld", (long) parcKeyValue_GetKey(entry));
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *key = parcTreeMap_GetFirstKey(tree);
+
+ assertTrue(_int_Equals(data->k[1], key), "Wrong value, got %ld", (long) key);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstKey_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCObject *key = parcTreeMap_GetFirstKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastKey_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCObject *key = parcTreeMap_GetLastKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCKeyValue *entry = parcTreeMap_GetLastEntry(tree);
+
+ assertTrue(_int_Equals(data->k[39], parcKeyValue_GetKey(entry)),
+ "Wrong value, got %ld", (long) parcKeyValue_GetKey(entry));
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *key = parcTreeMap_GetLastKey(tree);
+
+ assertTrue(_int_Equals(data->k[39], key), "Wrong value, got %ld", (long) key);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_First)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[1], data->v[1]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[1]);
+ parcObject_Release(&value);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[30], data->v[30]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[30]);
+ parcObject_Release(&value);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Last)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[41], data->v[41]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[41]);
+ assertNotNull(value, "Expected to find some object.");
+ assertTrue(_int_Equals(data->v[41], value), "Expected value 41 in return");
+ parcObject_Release(&value);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees don't match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_First)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[1], data->v[1]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[1]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[30], data->v[30]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[30]);
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+
+ for (int i = 20; i < 30; i++) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[i]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[49 - i]);
+ }
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+
+ for (int i = 2; i < 10; i++) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[i]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[11 - i]);
+ }
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+
+ for (int i = 31; i < 40; i++) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[i]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[70 - i]);
+ }
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_NonExistent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *element = parcTreeMap_Remove(tree1, data->k[0]);
+
+ assertNull(element, "Return value must be NULL on non existing element");
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_NonExistent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[0]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_WithSuccessorNonRoot)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+ int idx2[13] = { 8, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ for (int i = 0; i < 13; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree2, data->k[idx2[i]], data->v[idx2[i]]);
+ }
+
+ _Int *key = _int_Create(4);
+ parcTreeMap_RemoveAndRelease(tree1, key);
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 12));
+ _int_Release(&key);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_LeftChildRightChild)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ parcTreeMap_Put(tree2, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ _Int *key = _int_Create(0);
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 13));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 7));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 14));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 6));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 15));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 12));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 11));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 10));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 9));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 8));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 5));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 4));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 3));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 2));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 1));
+
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 1));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 2));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 3));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 4));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 5));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 6));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 7));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 8));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 9));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 10));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 11));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 12));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 13));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 14));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 15));
+ _int_Release(&key);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_Last)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ parcTreeMap_Put(tree1, data->k[41], data->v[41]);
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[41]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LowerEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ PARCKeyValue *kv = parcTreeMap_GetLowerEntry(tree1, data->k[23]);
+ assertNull(kv, "Expected a NULL return for LowerEntry() on empty tree");
+
+ // Fill Tree
+ int max = N_TEST_ELEMENTS - 1;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Using lowest key in tree
+ kv = parcTreeMap_GetLowerEntry(tree1, data->k[1]);
+ assertNull(kv, "Expected a NULL return for no lower entry");
+
+ // On all entries except the lowest tree
+ for (int i = max; i > 1; --i) {
+ kv = parcTreeMap_GetLowerEntry(tree1, data->k[i]);
+ assertNotNull(kv, "Expected a lower entry to exist");
+ _Int *key = (_Int *) parcKeyValue_GetKey(kv);
+ assertTrue(_int_Equals(key, data->k[i - 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i - 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LowerKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ _Int *key = (_Int *) parcTreeMap_GetLowerKey(tree1, data->k[23]);
+ assertNull(key, "Expected a NULL return for LowerEntry() on empty tree");
+
+ int max = N_TEST_ELEMENTS - 1;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Using lowest key in tree
+ key = (_Int *) parcTreeMap_GetLowerKey(tree1, data->k[1]);
+ assertNull(key, "Expected a NULL return for no lower entry");
+
+ // On all entries except the lowest tree
+ for (int i = max; i > 1; --i) {
+ key = parcTreeMap_GetLowerKey(tree1, data->k[i]);
+ assertNotNull(key, "Expected a lower entry to exist");
+ assertTrue(_int_Equals(key, data->k[i - 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i - 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_HigherEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ PARCKeyValue *kv = parcTreeMap_GetHigherEntry(tree1, data->k[23]);
+ assertNull(kv, "Expected a NULL return for HigherEntry() on empty tree");
+
+ int max = N_TEST_ELEMENTS - 2;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Using highest key in tree
+ kv = parcTreeMap_GetHigherEntry(tree1, data->k[max]);
+ assertNull(kv, "Expected a NULL return for no higher entry");
+
+ // On all entries except the lowest tree
+ for (int i = 1; i < max; ++i) {
+ kv = parcTreeMap_GetHigherEntry(tree1, data->k[i]);
+ assertNotNull(kv, "Expected a higher entry to exist");
+ _Int *key = (_Int *) parcKeyValue_GetKey(kv);
+ assertTrue(_int_Equals(key, data->k[i + 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i + 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_HigherKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ _Int *key = (_Int *) parcTreeMap_GetHigherKey(tree1, data->k[23]);
+ assertNull(key, "Expected a NULL return for LowerEntry() on empty tree");
+
+ int max = N_TEST_ELEMENTS - 2;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ key = (_Int *) parcTreeMap_GetHigherEntry(tree1, data->k[max]);
+ assertNull(key, "Expected a NULL return for no higher entry");
+
+ for (int i = 1; i < max; ++i) {
+ key = (_Int *) parcTreeMap_GetHigherKey(tree1, data->k[i]);
+ assertNotNull(key, "Expected a higher entry to exist");
+ assertTrue(_int_Equals(key, data->k[i + 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i + 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Keys)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+ // Insert in tree out of order
+ for (int i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Insert in list in order
+ for (int i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcList_Add(list, data->k[i]);
+ }
+
+ PARCList *keys = parcTreeMap_AcquireKeys(tree1);
+
+ assertTrue(parcList_Equals(list, keys), "Key list doesnt' match");
+
+ parcList_Release(&keys);
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Values)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+ // Insert in tree out of order
+ for (int i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Insert in list in order
+ for (int i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcList_Add(list, data->v[i]);
+ }
+
+ PARCList *values = parcTreeMap_AcquireValues(tree1);
+
+ assertTrue(parcList_Equals(list, values), "Key list doesnt' match");
+
+ parcList_Release(&values);
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Empty lists are not equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_DifferentLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree2, data->k[41], data->v[41]);
+
+ assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists are equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Values)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[20 - i]);
+ }
+
+ assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists are equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Keys)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i + 1], data->v[i]);
+ }
+ assertTrue(parcTreeMap_Size(tree1) == parcTreeMap_Size(tree2), "Expect trees to have the same size.");
+
+ assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists should not be equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 1; i < 40; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[40 - i], data->v[40 - i]);
+ }
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Lists are not equal");
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *treeCopy = parcTreeMap_Copy(tree1);
+
+ for (int i = 1; i < 10; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ assertFalse(parcTreeMap_Equals(tree1, treeCopy), "Lists are not equal");
+
+ parcTreeMap_Release(&treeCopy);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Copy_Direct)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ PARCTreeMap *treeCopy = parcTreeMap_Copy(tree1);
+
+ assertTrue(parcTreeMap_Equals(tree1, treeCopy), "Lists are not equal");
+
+ parcTreeMap_Release(&treeCopy);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_ValueIterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateValueIterator(tree1);
+
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ _Int *value = (_Int *) parcIterator_Next(it);
+ assertTrue(_int_Equals(value, data->v[idx]), "Expected value %d got %d", data->v[idx]->value, value->value);
+ }
+
+ parcIterator_Release(&it);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_KeyIterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateKeyIterator(tree1);
+
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ _Int *key = (_Int *) parcIterator_Next(it);
+ assertTrue(_int_Equals(key, data->k[idx]),
+ "Expected value %d got %d",
+ data->k[idx]->value,
+ key->value);
+ }
+
+ parcIterator_Release(&it);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Iterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1);
+
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ PARCKeyValue *kv = (PARCKeyValue *) parcIterator_Next(it);
+ assertTrue(_int_Equals((_Int *) parcKeyValue_GetKey(kv), data->k[idx]),
+ "Expected value %d got %d",
+ data->k[idx]->value,
+ ((_Int *) parcKeyValue_GetKey(kv))->value);
+ }
+
+ parcIterator_Release(&it);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Using_Iterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1);
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ parcIterator_Next(it);
+ parcIterator_Remove(it);
+ }
+ parcIterator_Release(&it);
+
+ assertTrue(parcTreeMap_Size(tree1) == 0, "Expect the tree to be empty after removes.");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Element_Using_Iterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 15, 13 }; //Missing 11
+
+ for (int i = 0; i < 14; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ parcTreeMap_Put(tree2, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[11], data->v[11]);
+
+
+ PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1);
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ parcIterator_Next(it);
+ if (idx == 11) {
+ parcIterator_Remove(it);
+ }
+ }
+ parcIterator_Release(&it);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Expect the trees to be equal after remove.");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ //LONGBOW_RUN_TEST_CASE(Local, PARC_TreeMap_EnsureRemaining_NonEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Stress)
+{
+ // LongBow could use a command line option to enable/disable tests
+ // See LongBow issue #5
+ if (getenv("LongBowStress")) {
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeededSmall);
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeeded);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeededSmall)
+{
+ unsigned seed;
+ char *seedString;
+
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+
+ for (int j = 0; j < 1; j++) {
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+
+ srandom(seed);
+ PARCTreeMap *tree = parcTreeMap_Create();
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100; i++) {
+ intptr_t item = 1 + (random() % 100);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeMap_Put(tree, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeMap_Remove(tree, (void *) item);
+ }
+ rbCheckTree(tree);
+ }
+
+ parcTreeMap_Release(&tree);
+ }
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeeded)
+{
+ PARCTreeMap *tree1;
+ unsigned seed;
+ char *seedString;
+
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+
+ srandom(seed);
+
+ tree1 = parcTreeMap_Create();
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100000; i++) {
+ intptr_t item = 1 + (random() % 10000);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeMap_Put(tree1, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeMap_Remove(tree1, (void *) item);
+ }
+ rbCheckTree(tree1);
+ }
+
+ parcTreeMap_Release(&tree1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_TreeMap);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_TreeRedBlack.c b/libparc/parc/algol/test/test_parc_TreeRedBlack.c
new file mode 100755
index 00000000..7fb1828a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_TreeRedBlack.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_TreeRedBlack.c"
+
+
+void *
+keyNewInt(int key)
+{
+ int *newKey = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ *newKey = key;
+ return newKey;
+}
+
+void *
+valueNewInt(int value)
+{
+ int *newValue = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ *newValue = value;
+ return newValue;
+}
+
+void *
+keyCopy(const void *key)
+{
+ return keyNewInt(*(int *) key);
+}
+
+void *
+valueCopy(const void *value)
+{
+ return valueNewInt(*(int *) value);
+}
+
+void *
+keyNew(char *key)
+{
+ return parcMemory_StringDuplicate(key, strlen(key));
+}
+
+void *
+valueNew(char *value)
+{
+ return parcMemory_StringDuplicate(value, strlen(value));
+}
+
+int
+intComp(const void *key1, const void *key2)
+{
+ if (*(int *) key1 < *(int *) key2) {
+ return -1;
+ }
+ if (*(int *) key1 == *(int *) key2) {
+ return 0;
+ }
+ return 1;
+}
+
+bool
+intEquals(const void *int1, const void *int2)
+{
+ return intComp(int1, int2) == 0;
+}
+
+int
+pointerComp(const void *key1, const void *key2)
+{
+ if (key1 < key2) {
+ return -1;
+ }
+ if (key1 == key2) {
+ return 0;
+ }
+ return 1;
+}
+
+int
+stringComp(const void *key1, const void *key2)
+{
+ // We assume all keys are strings.
+ return strcmp(key1, key2);
+}
+
+void
+keyFree(void **value)
+{
+ parcMemory_Deallocate((void **) value);
+ *value = NULL;
+}
+
+void
+valueFree(void **key)
+{
+ parcMemory_Deallocate((void **) key);
+ *key = NULL;
+}
+
+
+LONGBOW_TEST_RUNNER(PARC_TreeRedBlack)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Stress);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_TreeRedBlack)
+{
+ int seed = (int) time(NULL);
+ printf("Seed = %u\n", seed);
+ srandom(seed);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_TreeRedBlack)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Create);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_OutOfOrder);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_DestroyTillEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_EmptyTree);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Biggest);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Smallest);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_WithSuccessorNonRoot);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_LeftChildRightChild);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Func);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_DifferentLength);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values_Func);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Copy_Direct);
+ //LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_ExerciseRandom);
+ //LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_ExerciseRootFailure);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ /*
+ * uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ * if (outstandingAllocations != 0) {
+ * printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ * return LONGBOW_STATUS_MEMORYLEAK;
+ * }
+ */
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static
+int
+strComp(const void *s1, const void *s2)
+{
+ return strcmp((char *) s1, (char *) s2);
+}
+
+static
+bool
+strEquals(const void *s1, const void *s2)
+{
+ return strcmp(s1, s2) == 0;
+}
+
+static
+int
+recursiveCheckBlackDepth(const PARCTreeRedBlack *tree, const Node *node)
+{
+ assertNotNull(tree, "Null tree?\n");
+ assertNotNull(node, "Null node?\n");
+ if (node == tree->nil) {
+ return 0;
+ }
+ int right_depth = recursiveCheckBlackDepth(tree, node->right_child);
+ int left_depth = recursiveCheckBlackDepth(tree, node->left_child);
+ assertTrue(right_depth == left_depth, "Wrong depth!!\n");
+ if (_rbNodeColor(node) == BLACK) {
+ return right_depth + 1;
+ }
+ return right_depth;
+}
+
+static
+void
+rbCheckTree(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ //printf("--- TREE ---\n");
+ if (tree->size > 0) {
+ //_rbNodeRecursiveRun((PARCTreeRedBlack *)tree,tree->root,rbCheckNode,(void *)tree);
+ recursiveCheckBlackDepth(tree, tree->root);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Ordered)
+{
+ char *insertList[16] = {
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ "08",
+ "09",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16"
+ };
+
+ PARCTreeRedBlack *tree1;
+
+ tree1 = parcTreeRedBlack_Create(strComp, NULL, NULL, strEquals, NULL, NULL);
+
+ for (int i = 0; i < 16; i++) {
+ parcTreeRedBlack_Insert(tree1, insertList[i], insertList[i]);
+ }
+
+ for (int i = 0; i < 14; i++) {
+ //rbPrintTreeString(tree1);
+ void *data = parcTreeRedBlack_Remove(tree1, insertList[i]);
+ assertNotNull(data, "Data is null!");
+ }
+
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Create)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(stringComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Destroy(&tree);
+
+ tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Destroy)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL);
+
+ void *value1 = valueNew("value 1");
+ void *key1 = keyNew("1");
+ void *value2 = valueNew("value 2");
+ void *key2 = keyNew("2");
+ void *value3 = valueNew("value 3");
+ void *key3 = keyNew("3");
+
+ parcTreeRedBlack_Insert(tree, key1, value1);
+ parcTreeRedBlack_Insert(tree, key2, value2);
+ parcTreeRedBlack_Insert(tree, key3, value3);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Overwrite)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL);
+
+ parcTreeRedBlack_Insert(tree, keyNew("1"), valueNew("v1"));
+ parcTreeRedBlack_Insert(tree, keyNew("2"), valueNew("v2"));
+ parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v3"));
+ parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v4"));
+ parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v5"));
+
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree should stay at 3");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Ordered)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_OutOfOrder)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size_Empty)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ assertTrue(0 == parcTreeRedBlack_Size(tree), "Wrong size of tree - empty, start");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size)
+{
+ PARCTreeRedBlack *tree;
+ size_t size;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 3");
+
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+
+ assertTrue(4 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 2);
+
+ size = parcTreeRedBlack_Size(tree);
+
+ assertTrue(3 == size, "Wrong size of tree after 1 delete (%zu instead of 3)", size);
+
+ parcTreeRedBlack_Insert(tree, (void *) 7, (void *) 1007);
+
+ assertTrue(4 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 3);
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after del 1 more - 3");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_DestroyTillEmpty)
+{
+ PARCTreeRedBlack *tree;
+ size_t size;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 5, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 7, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 6, (void *) 1001);
+
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 3);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 1);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 2);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 6);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 5);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 7);
+
+ size = parcTreeRedBlack_Size(tree);
+
+ assertTrue(0 == size, "Wrong size of tree - empty (got %zu)", size);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size_Overwrite)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+
+ // Size is 3 here, we'll insert the same number now..
+
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1033);
+
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after overwrite");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_EmptyTree)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 1);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_NonExistent)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 100);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_First)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 4; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 1);
+
+ assertTrue((1 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 4);
+
+ assertTrue((4 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Last)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 9);
+
+ assertTrue((9 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Smallest)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 1);
+
+ assertTrue((1 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Biggest)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 39);
+
+ assertTrue((39 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *key = parcTreeRedBlack_FirstKey(tree);
+
+ assertTrue(1 == (long) key, "Wrong value, got %ld", (long) key);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey_Empty)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ void *key = parcTreeRedBlack_FirstKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey_Empty)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ void *key = parcTreeRedBlack_LastKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *key = parcTreeRedBlack_LastKey(tree);
+
+ assertTrue(39 == (long) key, "Wrong value, got %ld", (long) key);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_First)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, keyNewInt(1), valueNewInt(1 << 8));
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ int searchKey = 1;
+
+ void *data = parcTreeRedBlack_Remove(tree1, &searchKey);
+
+ valueFree(&data);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, keyNewInt(30), valueNewInt(31 << 8));
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ int searchKey = 30;
+
+ void *data = parcTreeRedBlack_Remove(tree1, &searchKey);
+
+ valueFree(&data);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Last)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+ parcTreeRedBlack_Insert(tree1, keyNewInt(100), valueNewInt(100 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ int searchKey = 100;
+
+ void *data = parcTreeRedBlack_Remove(tree1, &searchKey);
+
+ valueFree(&data);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_First)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, (void *) 1, (void *) (1 << 8));
+
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 1);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, (void *) 30, (void *) (30 << 8));
+
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 30);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_NonExistent)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ void *element = parcTreeRedBlack_Remove(tree1, (void *) 100);
+
+ assertNull(element, "Return value must be NULL on non existing element");
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_NonExistent)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 100);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_WithSuccessorNonRoot)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ long insert1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+ long insert2[13] = { 8, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) insert1[i], (void *) (insert1[i] << 8));
+ }
+
+ for (int i = 0; i < 13; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree2, (void *) insert2[i], (void *) (insert2[i] << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 12);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_LeftChildRightChild)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ long insert1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+ long insert2[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) insert1[i], (void *) (insert1[i] << 8));
+ }
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree2, (void *) insert2[i], (void *) (insert2[i] << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 13);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 7);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 14);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 6);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 15);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 12);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 11);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 10);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 9);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 8);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 5);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 3);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 2);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 1);
+
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 1);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 2);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 3);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 5);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 6);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 7);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 8);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 9);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 10);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 11);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 12);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 13);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 14);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 15);
+
+ //assertTrue(parcTreeRedBlack_Equals(tree1,tree2),"Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_Last)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ parcTreeRedBlack_Insert(tree1, (void *) 100, (void *) (100 << 8));
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 100);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Keys)
+{
+ PARCTreeRedBlack *tree1;
+ PARCArrayList *list;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ list = parcArrayList_Create(NULL);
+
+ // Insert in tree out of order
+ for (long i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+
+ // Insert in list in order
+ for (long i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcArrayList_Add(list, (void *) i);
+ }
+
+ PARCArrayList *keys = parcTreeRedBlack_Keys(tree1);
+
+ assertTrue(parcArrayList_Equals(list, keys), "Key list doesnt' match");
+
+ parcArrayList_Destroy(&keys);
+ parcArrayList_Destroy(&list);
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Values)
+{
+ PARCTreeRedBlack *tree1;
+ PARCArrayList *list;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ list = parcArrayList_Create(NULL);
+
+ // Insert in tree out of order
+ for (long i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+
+ // Insert in list in order
+ for (long i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcArrayList_Add(list, (void *) (i << 8));
+ }
+
+ PARCArrayList *values = parcTreeRedBlack_Values(tree1);
+
+ assertTrue(parcArrayList_Equals(list, values), "Key list doesnt' match");
+
+ parcArrayList_Destroy(&values);
+ parcArrayList_Destroy(&list);
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Empty)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Empty lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_DifferentLength)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts - i),
+ (void *) ((compareInserts - i) << 8));
+ }
+ parcTreeRedBlack_Insert(tree2, (void *) (1000), (void *) ((12304) << 8));
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts - i),
+ (void *) ((compareInserts + i) << 8));
+ }
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values_Func)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+ tree2 = parcTreeRedBlack_Create(pointerComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+
+ for (int i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ keyNewInt(i),
+ valueNewInt(i + 1000));
+ parcTreeRedBlack_Insert(tree2,
+ keyNewInt(i),
+ valueNewInt(i + 2000));
+ }
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Keys)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts + i),
+ (void *) ((compareInserts - i) << 8));
+ }
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts - i),
+ (void *) ((compareInserts - i) << 8));
+ }
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Func)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+
+ for (int i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ keyNewInt(i),
+ valueNewInt(i + 1000));
+ parcTreeRedBlack_Insert(tree2,
+ keyNewInt(i),
+ valueNewInt(i + 1000));
+ }
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Copy)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 20;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+
+ for (int i = 1; i < compareInserts; i++) {
+ void *key = keyNewInt(i);
+ void *value = valueNewInt(i + 1000);
+ //value = (void *) &((*(int*)value) + 100);
+ parcTreeRedBlack_Insert(tree1, key, value);
+ }
+
+ tree2 = parcTreeRedBlack_Copy(tree1);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Copy_Direct)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 20;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ }
+
+ tree2 = parcTreeRedBlack_Copy(tree1);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ //LONGBOW_RUN_TEST_CASE(Local, PARC_TreeRedBlack_EnsureRemaining_NonEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Stress)
+{
+ // LongBow could use a command line option to enable/disable tests
+ // See LongBow issue #5
+ if (getenv("LongBowStress")) {
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeededSmall);
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeeded);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeededSmall)
+{
+ PARCTreeRedBlack *tree1;
+ unsigned seed;
+ char *seedString;
+
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+
+ for (int j = 0; j < 1; j++) {
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+
+ printf("Random seed %u\n", seed);
+
+ srandom(seed);
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100; i++) {
+ intptr_t item = 1 + (random() % 100);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeRedBlack_Insert(tree1, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeRedBlack_Remove(tree1, (void *) item);
+ }
+ rbCheckTree(tree1);
+ }
+
+ parcTreeRedBlack_Destroy(&tree1);
+ }
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeeded)
+{
+ PARCTreeRedBlack *tree1;
+ unsigned seed;
+ char *seedString;
+
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+ printf("Random seed %u\n", seed);
+
+ srandom(seed);
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100000; i++) {
+ intptr_t item = 1 + (random() % 10000);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeRedBlack_Insert(tree1, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeRedBlack_Remove(tree1, (void *) item);
+ }
+ rbCheckTree(tree1);
+ }
+
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_TreeRedBlack);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_URI.c b/libparc/parc/algol/test/test_parc_URI.c
new file mode 100644
index 00000000..5050deb3
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URI.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *
+ */
+#include "../parc_URI.c"
+#include <LongBow/unit-test.h>
+
+#include <stdint.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_Hash.h>
+
+#include "_test_parc_URI.h"
+
+LONGBOW_TEST_RUNNER(parcURI)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURI);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURI)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURI)
+{
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_Only);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_BadScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_EmptyScheme);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority_NoAuthority);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority_NoPath);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Acquire);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_AuthorityEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_AuthorityEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_QueryEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_QueryEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_FragmentEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_FragmentEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SchemeEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SchemeEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse_NoScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse_SchemeOnly);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Equals_Contract);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetPath);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetQuery);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetFragment);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Copy);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_ToString_Full);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, PARCURI_ToString_SchemeOnly);
+ LONGBOW_RUN_TEST_CASE(parcURI, PARCURI_ToString_NoAuthority);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Acquire)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+
+ PARCURI *handle = parcURI_Acquire(uri);
+
+ assertTrue(parcURI_Equals(uri, handle), "Expected URI and acquired handle to be equal");
+
+ parcURI_Release(&handle);
+ parcURI_Release(&uri);
+ parcMemory_Deallocate((void **) &uriString);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_AuthorityEquals_SamePointer)
+{
+ char *authority = "authority@auth";
+ assertTrue(_parcURI_AuthorityEquals(authority, authority),
+ "Expected authorities to be equal since they're the same pointers: %p - %p",
+ (void *) authority, (void *) authority);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_AuthorityEquals_NullPointers)
+{
+ char *authority = "authority@auth";
+ assertFalse(_parcURI_AuthorityEquals(NULL, authority), "Expected authorities to not be equal since one is NULL");
+ assertFalse(_parcURI_AuthorityEquals(authority, NULL), "Expected authorities to not be equal since one is NULL");
+ assertTrue(_parcURI_AuthorityEquals(NULL, NULL), "Expected authorities to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_QueryEquals_SamePointer)
+{
+ char *query = "query";
+ assertTrue(_parcURI_QueryEquals(query, query),
+ "Expected queries to be equal since they're the same pointers: %p - %p",
+ (void *) query, (void *) query);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_QueryEquals_NullPointers)
+{
+ char *query = "query";
+ assertFalse(_parcURI_QueryEquals(NULL, query), "Expected queries to not be equal since one is NULL");
+ assertFalse(_parcURI_QueryEquals(query, NULL), "Expected queries to not be equal since one is NULL");
+ assertTrue(_parcURI_QueryEquals(NULL, NULL), "Expected queries to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_FragmentEquals_SamePointer)
+{
+ char *fragment = "fragment";
+ assertTrue(_parcURI_FragmentEquals(fragment, fragment),
+ "Expected fragments to be equal since they're the same pointers: %p - %p",
+ (void *) fragment, (void *) fragment);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_FragmentEquals_NullPointers)
+{
+ char *fragment = "fragment";
+ assertFalse(_parcURI_FragmentEquals(NULL, fragment), "Expected fragments to not be equal since one is NULL");
+ assertFalse(_parcURI_FragmentEquals(fragment, NULL), "Expected fragments to not be equal since one is NULL");
+ assertTrue(_parcURI_FragmentEquals(NULL, NULL), "Expected fragments to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SchemeEquals_SamePointer)
+{
+ char *scheme = "scheme";
+ assertTrue(_parcURI_SchemeEquals(scheme, scheme),
+ "Expected schemes to be equal since they're the same pointers: %p - %p",
+ (void *) scheme, (void *) scheme);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SchemeEquals_NullPointers)
+{
+ char *scheme = "scheme";
+ assertFalse(_parcURI_SchemeEquals(NULL, scheme), "Expected schemes to not be equal since one is NULL");
+ assertFalse(_parcURI_SchemeEquals(scheme, NULL), "Expected schemes to not be equal since one is NULL");
+ assertTrue(_parcURI_SchemeEquals(NULL, NULL), "Expected schemes to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme_EmptyScheme)
+{
+ const char *pointer;
+ char *actual = _parseScheme(":", &pointer); // empty string
+ assertNull(actual, "Parsed scheme should be NULL since the input string was empty.");
+ actual = _parseScheme("", &pointer); // empty string
+ assertNull(actual, "Parsed scheme should be NULL since the input string was empty.");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Parse)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+ assertNotNull(uri, "Expected non-null result for '%s'", uriString);
+
+ memset(uriString, 0, strlen(uriString));
+
+ assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri));
+ assertTrue(strcmp(URI_AUTHORITY, parcURI_GetAuthority(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_AUTHORITY, parcURI_GetAuthority(uri));
+ assertTrue(strcmp(URI_QUERY, parcURI_GetQuery(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_QUERY, parcURI_GetQuery(uri));
+ assertTrue(strcmp(URI_FRAGMENT, parcURI_GetFragment(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_FRAGMENT, parcURI_GetFragment(uri));
+
+ parcMemory_Deallocate((void **) &uriString);
+
+ parcURI_Release(&uri);
+ assertNull(uri, "Expected parcURI_Release to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Parse_NoScheme)
+{
+ char *uriString = "/" URI_PATH_SEGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+ assertNull(uri,
+ "Expected null result for '%s'", uriString);
+ parcMemory_Deallocate((void **) &uriString);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Parse_SchemeOnly)
+{
+ char *uriString = URI_SCHEME ":";
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+ assertNotNull(uri,
+ "Expected non-null result for '%s'", uriString);
+
+ memset(uriString, 0, strlen(uriString));
+
+ assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri));
+ assertNull(parcURI_GetAuthority(uri),
+ "Expected NULL, actual '%s'", parcURI_GetAuthority(uri));
+ assertNull(parcURI_GetQuery(uri),
+ "Expected NULL, actual '%s'", parcURI_GetQuery(uri));
+ assertNull(parcURI_GetFragment(uri),
+ "Expected NULL, actual '%s'", parcURI_GetFragment(uri));
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+ assertNull(uri,
+ "Expected parcURI_Release to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme)
+{
+ const char *pointer;
+ char *actual = _parseScheme(URI_FULL, &pointer);
+ assertTrue(strcmp(URI_SCHEME, actual) == 0,
+ "Expected '%s' actual '%s'", URI_SCHEME, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme_Only)
+{
+ const char *pointer;
+ char *actual = _parseScheme(URI_SCHEME ":", &pointer);
+ assertTrue(strcmp(URI_SCHEME, actual) == 0,
+ "Expected '%s' actual '%s'", URI_SCHEME, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme_BadScheme)
+{
+ const char *pointer;
+ char *actual = _parseScheme("", &pointer);
+ assertNull(actual,
+ "Expected NULL actual '%s'", actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_GetAuthority)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetAuthority(uri);
+ assertTrue(strcmp(TEST_URI_AUTHORITY, actual) == 0,
+ "Expected '%s' actual '%s'", URI_AUTHORITY, actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_GetQuery)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetQuery(uri);
+ assertTrue(strcmp(URI_QUERY, actual) == 0,
+ "Expected '%s' actual '%s'", URI_FRAGMENT, actual);
+
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_GetFragment)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetFragment(uri);
+ assertTrue(strcmp(URI_FRAGMENT, actual) == 0,
+ "Expected '%s' actual '%s'", URI_FRAGMENT, actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_GetPath)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIPath *actual = parcURI_GetPath(uri);
+
+ char *string = parcURIPath_ToString(actual);
+
+ char *expected = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expected, string) == 0, "Expected '%s' actual '%s'", expected, string);
+
+ parcMemory_Deallocate((void **) &string);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Copy)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *uri2 = parcURI_Copy(uri);
+
+ char *expected = parcURI_ToString(uri);
+ char *actual = parcURI_ToString(uri2);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &expected);
+ parcMemory_Deallocate((void **) &actual);
+ parcURI_Release(&uri);
+ parcURI_Release(&uri2);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Equals_Contract)
+{
+ PARCURI *x = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *y = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *z = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *u = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY);
+
+ parcObjectTesting_AssertEqualsFunction(parcURI_Equals, x, y, z, u);
+
+ parcURI_Release(&x);
+ parcURI_Release(&y);
+ parcURI_Release(&z);
+ parcURI_Release(&u);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_GetScheme)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetScheme(uri);
+ assertTrue(strcmp(TEST_URI_SCHEME, actual) == 0,
+ "Expected '%s' actual '%s'", TEST_URI_SCHEME, actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_Parse)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ assertNotNull(uri,
+ "Expected a non-null result.");
+
+ assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri));
+ assertTrue(strcmp(URI_AUTHORITY, parcURI_GetAuthority(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_AUTHORITY, parcURI_GetAuthority(uri));
+ assertTrue(strcmp(URI_QUERY, parcURI_GetQuery(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_QUERY, parcURI_GetQuery(uri));
+ assertTrue(strcmp(URI_FRAGMENT, parcURI_GetFragment(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_FRAGMENT, parcURI_GetFragment(uri));
+
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_ToString_Full)
+{
+ char *expected = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ PARCURI *uri = parcURI_Parse(expected);
+ char *actual = parcURI_ToString(uri);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_ToString_SchemeOnly)
+{
+ char *expected = URI_SCHEME ":" "/";
+ PARCURI *uri = parcURI_Parse(expected);
+ char *actual = parcURI_ToString(uri);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcURI_Release(&uri);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_ToString_NoAuthority)
+{
+ char *expected = URI_SCHEME ":" "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ PARCURI *uri = parcURI_Parse(expected);
+ char *actual = parcURI_ToString(uri);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+
+ parcURI_Release(&uri);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseAuthority)
+{
+ char *authority = "//" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ char *expected = URI_AUTHORITY;
+
+ const char *pointer;
+ char *actual = _parseAuthority(authority, &pointer);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ assertTrue(*pointer == '/',
+ "Expected '/' actual '%c'", *pointer);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseAuthority_NoAuthority)
+{
+ char *string = "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+
+ const char *pointer;
+ char *actual = _parseAuthority(string, &pointer);
+ assertTrue(actual == NULL,
+ "Expected NULL actual '%s'", actual);
+ assertTrue(*pointer == '/',
+ "Expected '/' actual '%c'", *pointer);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme)
+{
+ char *scheme = "scheme";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetScheme(uri, scheme);
+
+ assertTrue(strcmp(scheme, parcURI_GetScheme(uri)) == 0,
+ "Expected %s actual %s", scheme, parcURI_GetScheme(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme_Resetting)
+{
+ char *scheme = "scheme";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetScheme(uri, scheme);
+ _parcURI_SetScheme(uri, scheme);
+
+ assertTrue(strcmp(scheme, parcURI_GetScheme(uri)) == 0,
+ "Expected %s actual %s", scheme, parcURI_GetScheme(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme_Reset)
+{
+ char *scheme = "scheme";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetScheme(uri, scheme);
+ _parcURI_SetScheme(uri, NULL);
+
+ assertNull(parcURI_GetScheme(uri),
+ "Expected NULL actual %s", parcURI_GetScheme(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment)
+{
+ char *fragment = "fragment";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetFragment(uri, fragment);
+
+ assertTrue(strcmp(fragment, parcURI_GetFragment(uri)) == 0,
+ "Expected %s actual %s", fragment, parcURI_GetFragment(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment_Resetting)
+{
+ char *fragment = "fragment";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetFragment(uri, fragment);
+ _parcURI_SetFragment(uri, fragment);
+
+ assertTrue(strcmp(fragment, parcURI_GetFragment(uri)) == 0,
+ "Expected %s actual %s", fragment, parcURI_GetFragment(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment_Reset)
+{
+ char *fragment = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetFragment(uri, fragment);
+ _parcURI_SetFragment(uri, NULL);
+
+ assertNull(parcURI_GetFragment(uri),
+ "Expected NULL actual %s", parcURI_GetFragment(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetQuery(uri, query);
+
+ assertTrue(strcmp(query, parcURI_GetQuery(uri)) == 0,
+ "Expected %s actual %s", query, parcURI_GetQuery(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery_Resetting)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetQuery(uri, query);
+ _parcURI_SetQuery(uri, query);
+
+ assertTrue(strcmp(query, parcURI_GetQuery(uri)) == 0,
+ "Expected %s actual %s", query, parcURI_GetQuery(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery_Reset)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetQuery(uri, query);
+ _parcURI_SetQuery(uri, NULL);
+
+ assertNull(parcURI_GetQuery(uri),
+ "Expected NULL actual %s", parcURI_GetQuery(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority)
+{
+ char *authority = "authority@auth";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetAuthority(uri, authority);
+
+ assertTrue(strcmp(authority, parcURI_GetAuthority(uri)) == 0,
+ "Expected %s actual %s", authority, parcURI_GetAuthority(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority_Resetting)
+{
+ char *authority = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetAuthority(uri, authority);
+ _parcURI_SetAuthority(uri, authority);
+
+ assertTrue(strcmp(authority, parcURI_GetAuthority(uri)) == 0,
+ "Expected %s actual %s", authority, parcURI_GetAuthority(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority_Reset)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetAuthority(uri, query);
+ _parcURI_SetAuthority(uri, NULL);
+
+ assertNull(parcURI_GetAuthority(uri),
+ "Expected NULL actual %s", parcURI_GetAuthority(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseAuthority_NoPath)
+{
+ char *authority = "//" URI_AUTHORITY;
+ char *expected = URI_AUTHORITY;
+
+ const char *pointer;
+ char *actual = _parseAuthority(authority, &pointer);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", authority, actual);
+ assertTrue(*pointer == 0,
+ "Expected null actual '%c'", *pointer);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseFragment)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(parcURI, parsePath)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(parcURI, parseQuery)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURI);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_URIAuthority.c b/libparc/parc/algol/test/test_parc_URIAuthority.c
new file mode 100644
index 00000000..e6d8196a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URIAuthority.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_URIAuthority.c"
+#include <stdint.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include "_test_parc_URI.h"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcURIAuthority)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURIAuthority);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURIAuthority)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURIAuthority)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURIAuthority)
+{
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Parse);
+
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Acquire);
+
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Equals);
+
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetUserInfo);
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetHostName);
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetPort);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURIAuthority)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURIAuthority)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Parse)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetUserInfo(authority), URI_AUTHORITY_USERINFO);
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+
+ // URI without the port
+ uriString = URI_SCHEME "://" URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetUserInfo(authority), URI_AUTHORITY_USERINFO);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ // URI with literal V4 address
+ uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ // URI with literal V6 address
+ uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST6 "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME6);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ // URI with full literal V6 address
+ uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST6_2 "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME6_2);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ parcMemory_Deallocate((void **) &uriString);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Acquire)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ PARCURIAuthority *handle = parcURIAuthority_Acquire(authority);
+
+ assertTrue(parcURIAuthority_Equals(authority, handle), "URI Authorities should be equal since they refer to the same object.");
+
+ parcURIAuthority_Release(&authority);
+ parcURIAuthority_Release(&handle);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Equals)
+{
+ char *uriString1 = URI_SCHEME "://" URI_AUTHORITY;
+ uriString1 = parcMemory_StringDuplicate(uriString1, strlen(uriString1));
+ PARCURI *uri1 = parcURI_Parse(uriString1);
+ PARCURIAuthority *x = parcURIAuthority_Parse(parcURI_GetAuthority(uri1));
+
+ char *uriString2 = URI_SCHEME "://" URI_AUTHORITY;
+ uriString2 = parcMemory_StringDuplicate(uriString2, strlen(uriString2));
+ PARCURI *uri2 = parcURI_Parse(uriString2);
+ PARCURIAuthority *y = parcURIAuthority_Parse(parcURI_GetAuthority(uri2));
+
+ char *uriString3 = URI_SCHEME "://" URI_AUTHORITY;
+ uriString3 = parcMemory_StringDuplicate(uriString3, strlen(uriString3));
+ PARCURI *uri3 = parcURI_Parse(uriString3);
+ PARCURIAuthority *z = parcURIAuthority_Parse(parcURI_GetAuthority(uri3));
+
+ char *differentUriString = URI_SCHEME "://" URI_AUTHORITY_USERINFO;
+ differentUriString = parcMemory_StringDuplicate(differentUriString, strlen(differentUriString));
+ PARCURI *unequalUri = parcURI_Parse(differentUriString);
+ PARCURIAuthority *u = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri));
+
+ char *uriString5 = URI_SCHEME "://" URI_AUTHORITY_DIFFERENT_PORT;
+ uriString5 = parcMemory_StringDuplicate(uriString5, strlen(uriString5));
+ PARCURI *unequalUri5 = parcURI_Parse(uriString5);
+ PARCURIAuthority *u5 = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri5));
+
+ char *uriString4 = URI_SCHEME "://" URI_AUTHORITY_DIFFERENT_USER;
+ uriString4 = parcMemory_StringDuplicate(uriString4, strlen(uriString4));
+ PARCURI *unequalUri4 = parcURI_Parse(uriString4);
+ PARCURIAuthority *u4 = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri4));
+
+ parcObjectTesting_AssertEqualsFunction(parcURIAuthority_Equals, x, y, z, u);
+
+ assertFalse(parcURIAuthority_Equals(x, u4), "Expected URI authorities with different user info to be unequal");
+ assertFalse(parcURIAuthority_Equals(x, u5), "Expected URI authorities with different hsot names to be unequal");
+
+ parcURIAuthority_Release(&x);
+ parcURIAuthority_Release(&y);
+ parcURIAuthority_Release(&z);
+ parcURIAuthority_Release(&u);
+ parcURIAuthority_Release(&u4);
+ parcURIAuthority_Release(&u5);
+
+ parcMemory_Deallocate((void **) &uriString1);
+ parcMemory_Deallocate((void **) &uriString2);
+ parcMemory_Deallocate((void **) &uriString3);
+ parcMemory_Deallocate((void **) &uriString4);
+ parcMemory_Deallocate((void **) &uriString5);
+ parcMemory_Deallocate((void **) &differentUriString);
+
+ parcURI_Release(&uri1);
+ parcURI_Release(&uri2);
+ parcURI_Release(&uri3);
+ parcURI_Release(&unequalUri);
+ parcURI_Release(&unequalUri4);
+ parcURI_Release(&unequalUri5);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetUserInfo)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertTrue(strcmp(URI_AUTHORITY_USERINFO, parcURIAuthority_GetUserInfo(authority)) == 0, "URI Authority user info should be equal: %s - %s", URI_AUTHORITY_USERINFO, parcURIAuthority_GetUserInfo(authority));
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetHostName)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertTrue(strcmp(URI_AUTHORITY_HOSTNAME, parcURIAuthority_GetHostName(authority)) == 0, "URI Authority host name should be equal: %s - %s", URI_AUTHORITY_HOSTNAME, parcURIAuthority_GetHostName(authority));
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetPort)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertTrue(atol(URI_AUTHORITY_PORT_1) == parcURIAuthority_GetPort(authority),
+ "URI Authority host name should be equal: %ld - %ld", atol(URI_AUTHORITY_PORT_1), parcURIAuthority_GetPort(authority));
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURIAuthority);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_URIPath.c b/libparc/parc/algol/test/test_parc_URIPath.c
new file mode 100644
index 00000000..29f34a96
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URIPath.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_URIPath.c"
+#include <stdint.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include "_test_parc_URI.h"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcURIPath)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURIPath);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURIPath)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURIPath)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURIPath)
+{
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Acquire);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Parse);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Parse_WithQuery);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Release);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Count);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Append);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_ToString);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Length);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Trim);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Copy);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Equals);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Identity);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Equal);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Unequal);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compose);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Equal);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Fail);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_BuildString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURIPath)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURIPath)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Acquire)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "//////" URI_PATH_SEGMENT, &pointer);
+ PARCURIPath *handle = parcURIPath_Acquire(path);
+
+ assertTrue(parcURIPath_Equals(path, handle), "URI paths should be equal: %s - %s", parcURIPath_ToString(path), parcURIPath_ToString(handle));
+
+ parcURIPath_Release(&path);
+ parcURIPath_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Parse)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "//////" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ char *actualPath = parcURIPath_ToString(path);
+
+ char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath);
+
+ parcMemory_Deallocate((void **) &actualPath);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Release)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ parcURIPath_Release(&path);
+ assertNull(path, "Expected destroy to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Parse_WithQuery)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == '?', "Expected pointer to point to the terminating character.");
+
+ char *actualPath = parcURIPath_ToString(path);
+ char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath);
+ parcMemory_Deallocate((void **) &actualPath);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Equals)
+{
+ const char *pointer;
+ PARCURIPath *x = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *y = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *z = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *u1 = parcURIPath_Parse("/" URI_PATH_SEGMENT "a/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *u2 = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+
+ parcObjectTesting_AssertEqualsFunction(parcURIPath_Equals, x, y, z, u1, u2);
+
+ parcURIPath_Release(&x);
+ parcURIPath_Release(&y);
+ parcURIPath_Release(&z);
+ parcURIPath_Release(&u1);
+ parcURIPath_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Copy)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *copy = parcURIPath_Copy(path);
+
+ assertTrue(copy != path, "Expected distinct instances of the path.");
+
+ int comparison = parcURIPath_Compare(path, copy);
+
+ assertTrue(comparison == 0, "Expected the copy to compare equal to the original.");
+
+ parcURIPath_Release(&path);
+ parcURIPath_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+
+ bool actual = parcURIPath_StartsWith(base, prefix);
+
+ assertTrue(actual, "Expected true, actual false.");
+
+ parcURIPath_Release(&prefix);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Equal)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ bool actual = parcURIPath_StartsWith(base, prefix);
+
+ assertTrue(actual, "Expected true, actual false.");
+
+ parcURIPath_Release(&prefix);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Fail)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix1 = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix2 = parcURIPath_Parse("/" URI_PATH_SEGMENT "A?query", &pointer);
+
+ assertFalse(parcURIPath_StartsWith(base, prefix1),
+ "Expected false, actual true");
+
+ assertFalse(parcURIPath_StartsWith(base, prefix2),
+ "Expected false, actual true");
+
+ parcURIPath_Release(&prefix1);
+ parcURIPath_Release(&prefix2);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compose)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *expected = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ PARCURISegment *a = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ PARCURIPath *actual = parcURIPath_Compose(base, a, a, NULL);
+ parcURISegment_Release(&a);
+
+ char *actualString = parcURIPath_ToString(actual);
+ char *expectedString = parcURIPath_ToString(expected);
+ assertTrue(parcURIPath_Compare(expected, actual) == 0, "Expected '%s' actual '%s'\n", expectedString, actualString);
+
+ parcMemory_Deallocate((void **) &actualString);
+ parcMemory_Deallocate((void **) &expectedString);
+
+ parcURIPath_Release(&actual);
+
+ parcURIPath_Release(&expected);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Identity)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ PARCURIPath *equivalents[] = {
+ path,
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query",&pointer),
+ NULL,
+ };
+ PARCURIPath *lessers[] = {
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer),
+ NULL,
+ };
+ PARCURIPath *greaters[] = {
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer),
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "AAA?query", &pointer),
+ NULL,
+ };
+
+ parcObjectTesting_AssertCompareTo(parcURIPath_Compare, path, equivalents, lessers, greaters);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ parcURIPath_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ parcURIPath_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ parcURIPath_Release(&greaters[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Equal)
+{
+ const char *pointer;
+ PARCURIPath *pathA = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *pathB = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ int comparison = parcURIPath_Compare(pathA, pathB);
+
+ assertTrue(comparison == 0, "Expected 0: equal paths to compare equal. Actual %d", comparison);
+ parcURIPath_Release(&pathA);
+ parcURIPath_Release(&pathB);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Unequal)
+{
+ const char *pointer;
+ PARCURIPath *pathA = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *pathB = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ int comparison = parcURIPath_Compare(pathA, pathB);
+
+ assertTrue(comparison < 0, "Expected < 0: path A is less than path B. Actual %d", comparison);
+ parcURIPath_Release(&pathA);
+ parcURIPath_Release(&pathB);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Count)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ size_t actual = parcURIPath_Count(path);
+ assertTrue(3 == actual, "Expected %d actual %zd", 3, actual);
+
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_ToString)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ char *actualString = parcURIPath_ToString(path);
+
+ char *expectedString = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedString, actualString) == 0, "Expected %s actual %s", expectedString, actualString);
+
+ parcMemory_Deallocate((void **) &actualString);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Length)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ size_t actualCount = parcURIPath_Length(path);
+
+ size_t expectedCount = 79;
+ assertTrue(expectedCount == actualCount, "Expected %zd actual %zd", expectedCount, actualCount);
+
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Append)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+
+ PARCURIPath *result = parcURIPath_Append(path, segment);
+ assertTrue(result == path, "Expected %p, actual %p", (void *) path, (void *) result);
+
+ size_t actualCount = parcURIPath_Count(path);
+ assertTrue(3 == actualCount, "Expected 3, actual %zd", actualCount);
+
+ char *actualPath = parcURIPath_ToString(path);
+ char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath);
+
+ parcMemory_Deallocate((void **) &actualPath);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Trim)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+
+ parcURIPath_Trim(path, 2);
+ size_t actualCount = parcURIPath_Count(path);
+ assertTrue(2 == actualCount, "Expected 2, actual %zd", actualCount);
+
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_BuildString)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT, &pointer);
+ PARCBufferComposer *target = parcBufferComposer_Create();
+
+ PARCBufferComposer *string = parcBufferComposer_Create();
+ parcBufferComposer_PutString(string, URI_PATH_SEGMENT);
+
+ PARCBuffer *b1 = parcBufferComposer_ProduceBuffer(string);
+ char *string1 = parcBuffer_ToString(b1);
+ parcBuffer_Release(&b1);
+
+ parcURIPath_BuildString(path, target);
+ PARCBuffer *b2 = parcBufferComposer_ProduceBuffer(target);
+ char *string2 = parcBuffer_ToString(b2);
+ parcBuffer_Release(&b2);
+
+ assertTrue(strncmp(string1, string2, strlen(string1)) == 0, "String representations of the paths should be equal: %s - %s", string1, string2);
+
+ parcMemory_Deallocate((void **) &string1);
+ parcMemory_Deallocate((void **) &string2);
+
+ parcBufferComposer_Release(&string);
+ parcBufferComposer_Release(&target);
+ parcURIPath_Release(&path);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURIPath);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_URISegment.c b/libparc/parc/algol/test/test_parc_URISegment.c
new file mode 100644
index 00000000..640bab89
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URISegment.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "../parc_URISegment.c"
+#include <LongBow/unit-test.h>
+
+#include <stdint.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include "_test_parc_URI.h"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcURISegment)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURISegment);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURISegment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURISegment)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURISegment)
+{
+ LONGBOW_RUN_TEST_CASE(parcURISegment, _parcURISegment_fromHexDigit);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, _parcURISegment_parsePercentEncoded);
+
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Acquire);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Create);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse_WithExtraSlashes);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse_WithInvalidPercentage);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Release);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Length);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_ToString);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Compare_Contract);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Clone);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_GetBuffer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURISegment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURISegment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURISegment, _parcURISegment_fromHexDigit)
+{
+ const char test = 'G';
+ signed char actual = _fromHexDigit(test);
+ assertTrue(-1 == (int) actual, "Invalid hex digit should not be changed to a decimal value, we expect -1 as the result");
+}
+
+LONGBOW_TEST_CASE(parcURISegment, _parcURISegment_parsePercentEncoded)
+{
+ unsigned char buffer;
+
+ const char *test1 = "0G";
+ const char *result1 = _parsePercentEncoded(test1, &buffer);
+ assertTrue(NULL == result1, "Expected NULL parsed byte from invalid encoded percentage string, got %s", result1);
+ const char *test2 = "GG";
+ const char *result2 = _parsePercentEncoded(test2, &buffer);
+ assertTrue(NULL == result2, "Expected NULL parsed byte from invalid encoded percentage string, got %s", result2);
+ const char *test3 = "";
+ const char *result3 = _parsePercentEncoded(test3, &buffer);
+ assertTrue(NULL == result3, "Expected NULL parsed byte from empty encoded percentage string, got %s", result3);
+ const char *test4 = "0";
+ const char *result4 = _parsePercentEncoded(test4, &buffer);
+ assertTrue(NULL == result4, "Expected NULL parsed byte from half-empty encoded percentage string, got %s", result4);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Acquire)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *handle = parcURISegment_Acquire(segment);
+ assertTrue(parcURISegment_Equals(segment, handle), "Expected URI segments to be equal: %s - %s", parcURISegment_ToString(segment), parcURISegment_ToString(handle));
+
+ parcURISegment_Release(&segment);
+ parcURISegment_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Create)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ PARCURISegment *segment = parcURISegment_Create(strlen(expected), (unsigned char *) expected);
+ assertNotNull(segment, "Expected non-null result.");
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+
+ char *expectedBytes = URI_PATH_SEGMENT;
+
+ char *actualBytes = parcURISegment_ToString(segment);
+
+ assertTrue(strcmp(expectedBytes, actualBytes) == 0,
+ "Expected %s actual %s", expectedBytes, actualBytes);
+ parcMemory_Deallocate((void **) &actualBytes);
+
+ assertTrue(parcURISegment_Length(segment) == 39,
+ "Expected 39, actual %zd", parcURISegment_Length(segment));
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse_WithExtraSlashes)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT_WITH_SLASHES, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+
+ char *expectedBytes = URI_PATH_SEGMENT;
+
+ char *actualBytes = parcURISegment_ToString(segment);
+
+ assertTrue(strcmp(expectedBytes, actualBytes) == 0,
+ "Expected %s actual %s", expectedBytes, actualBytes);
+ parcMemory_Deallocate((void **) &actualBytes);
+
+ assertTrue(parcURISegment_Length(segment) == 39,
+ "Expected 39, actual %zd", parcURISegment_Length(segment));
+ assertTrue(*pointer == '/', "Expected pointer to point to the slash character: %c", *pointer);
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse_WithInvalidPercentage)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT "%G", &pointer);
+
+ assertNull(segment, "Parsed segment should be NULL since the last percent-encoded byte is invalid");
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Release)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+
+ parcURISegment_Release(&segment);
+ assertNull(segment, "Expected destroy to null the pointer");
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Equals_Contract)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *x = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *y = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *z = parcURISegment_Parse(expected, &pointer);
+
+ parcObjectTesting_AssertEqualsFunction(parcURISegment_Equals, x, y, z, NULL);
+
+ parcURISegment_Release(&x);
+ parcURISegment_Release(&y);
+ parcURISegment_Release(&z);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Clone)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *copy = parcURISegment_Clone(segment);
+
+ assertTrue(segment != copy, "Expected different instances of equal segments.");
+
+ int comparison = parcURISegment_Compare(segment, copy);
+ assertTrue(comparison == 0, "Expected equal segments.");
+
+ assertTrue(parcURISegment_Equals(segment, copy), "Expected equal segments");
+
+ parcURISegment_Release(&copy);
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Length)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ assertNotNull(segment,
+ "Expected non-null result.");
+ assertTrue(*pointer == 0,
+ "Expected pointer to point to the null terminating byte.");
+
+ size_t actual = parcURISegment_Length(segment);
+
+ assertTrue(actual == 39,
+ "Expected 39, actual %zd", actual);
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Compare_Contract)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse("MMM", &pointer);
+
+ PARCURISegment *equivalents[] = {
+ segment,
+ parcURISegment_Parse("MMM",&pointer),
+ NULL,
+ };
+ PARCURISegment *lessers[] = {
+ parcURISegment_Parse("MM", &pointer),
+ parcURISegment_Parse("MML", &pointer),
+ NULL,
+ };
+ PARCURISegment *greaters[] = {
+ parcURISegment_Parse("MMMM", &pointer),
+ parcURISegment_Parse("MMN", &pointer),
+ NULL,
+ };
+ parcObjectTesting_AssertCompareTo(parcURISegment_Compare, segment, equivalents, lessers, greaters);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ parcURISegment_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ parcURISegment_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ parcURISegment_Release(&greaters[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_ToString)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ char *actual = parcURISegment_ToString(segment);
+
+ assertTrue(strcmp(URI_PATH_SEGMENT, actual) == 0, "Expected %s, actual %s", URI_PATH_SEGMENT, actual);
+
+ parcURISegment_Release(&segment);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_GetBuffer)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ PARCBuffer *buffer = parcURISegment_GetBuffer(segment);
+
+ char *expected = URI_PATH_SEGMENT;
+ char *actual = (char *) parcBuffer_Overlay(buffer, 0);
+ size_t compareLength = strlen(URI_PATH_SEGMENT);
+ assertTrue(strncmp(expected, actual, compareLength), "Buffer does not contain original data.");
+
+ parcURISegment_Release(&segment);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURISegment);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_Varint.c b/libparc/parc/algol/test/test_parc_Varint.c
new file mode 100755
index 00000000..cf0c865c
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Varint.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_Varint.c"
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+LONGBOW_TEST_RUNNER(parc_VarInt)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_VarInt)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_VarInt)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_And);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromByteBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUTF8ByteBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_New);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Or);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Set);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_ShiftLeft);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_ShiftRight);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_And)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint8)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsSize)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint8)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Destroy)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Equals)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint8)
+{
+ unsigned char expected = 5;
+ PARCVarint *a = parcVarint_FromUint8(expected);
+ PARCVarint *b = parcVarint_FromUint8(expected);
+
+ assertTrue(parcVarint_Equals(a, b), "Equal instances failed to be equal.");
+ parcVarint_Destroy(&a);
+ parcVarint_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromByteBuffer)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUTF8ByteBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "10");
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCVarint *varint = parcVarint_FromUTF8ByteBuffer(buffer);
+
+ uint32_t actual = parcVarint_AsUint32(varint);
+
+ assertTrue(10 == actual, "Expected 10 actual %u", actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+ parcVarint_Destroy(&varint);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUint32)
+{
+ uint32_t value = 0x12345678;
+ PARCVarint *a = parcVarint_FromUint32(value);
+ assertNotNull(a, "Probably out of memory.");
+
+ uint32_t actual = parcVarint_AsUint32(a);
+
+ assertEqual(value, actual, "%u");
+
+ parcVarint_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUint64)
+{
+ uint64_t value = 0x1234567812345678;
+ PARCVarint *a = parcVarint_FromUint64(value);
+ assertNotNull(a, "Probably out of memory.");
+
+ uint64_t actual = parcVarint_AsUint64(a);
+
+ assertEqual(value, actual, "%" PRIu64);
+
+ parcVarint_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUint8)
+{
+ uint8_t value = 0x12;
+ PARCVarint *a = parcVarint_FromUint8(value);
+ assertNotNull(a, "Probably out of memory.");
+
+ uint8_t actual = parcVarint_AsUint8(a);
+
+ assertEqual(value, actual, "%d");
+
+ parcVarint_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_New)
+{
+ PARCVarint *a = parcVarint_Create();
+ assertNotNull(a, "Probably out of memory.");
+
+ parcVarint_Destroy(&a);
+ assertNull(a, "Destroy failed to nullify.");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Or)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint8)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Set)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_ShiftLeft)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_ShiftRight)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_ToString)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_VarInt);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Vector.c b/libparc/parc/algol/test/test_parc_Vector.c
new file mode 100644
index 00000000..bea435dc
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Vector.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include "../parc_Vector.c"
+
+LONGBOW_TEST_RUNNER(PARCVector)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARCVector)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCVector)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ exit(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorGetLength);
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorGetPointer);
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorCreate);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorDestroy)
+{
+ const char *string = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) string, strlen(string));
+ parcVector_Destroy(&x);
+ assertNull(x, "Destroy did not nullify.");
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorGetLength)
+{
+ const char *string = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) string, strlen(string));
+ size_t expected = strlen(string);
+ size_t actual = parcVector_GetLength(x);
+ assertEqual(expected, actual, "%zd");
+ parcVector_Destroy(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorGetPointer)
+{
+ const char *expected = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) expected, strlen(expected));
+ const char *actual = parcVector_GetPointer(x);
+
+ assertEqual((void *) expected, (void *) actual, "%p");
+
+ parcVector_Destroy(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorCreate)
+{
+ const char *string = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) string, strlen(string));
+ assertNotNull(x, "Probably out of memory.");
+ parcVector_Destroy(&x);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCVector);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}