

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
/*! @file ComponentMemory.h
    @brief Shared-memory component registry: identity, location, parameters, private data and statistics for every component in the system.
    @ingroup Memory

    Components (modules, whiteboards, catalogs...) live inside space processes but are
    registered here so any process can resolve names/ids, check where a component runs
    (node/process), read or tweak its parameters, and follow its performance. The segment
    is one contiguous block: a ComponentMemoryStruct header, an index of uint64 offsets
    (one per component id), then variable-sized ComponentInfoStruct records each followed
    by their parameter and private-data areas. Records are relocated when they grow, so
    only offsets — never raw pointers — are stored.

    Component migration between processes/nodes is supported by copying the record's data
    area (getComponentData/setComponentData) and updating its location fields.

    @warning Shared-memory layouts; changing any struct here requires a full rebuild of
    all binaries (`make clean && make`) — see MemoryManager.h for the ABI warning. */

#if !defined(_COMPONENTMEMORY_H_)
#define _COMPONENTMEMORY_H_

#include "MemoryManager.h"
#include "PsyTime.h"
#include "Subscriptions.h"

namespace cmlabs {


/*! @name Component status values (ComponentInfoStruct::status)
    @{ */
#define COMPSTATUS_IDLE			1	/*!< Component idle, waiting for triggers. */
#define COMPSTATUS_STARTING		2	/*!< Component is starting up. */
#define COMPSTATUS_RUNNING		3	/*!< Component is executing a run. */
#define COMPSTATUS_FINISHED		4	/*!< Component finished/stopped. */
/*! @} */

/*! Sentinel for an unused index/queue slot. */
#define NOTINUSE	65535

/*! @name Component-record address helpers
    Navigate from the segment header to a component's offset slot and record. Offsets are
    relative to the end of the index area, so records can be relocated when they grow.
    @{ */
#define GETCOMPOFFSETP(header,id) (uint64*)(((char*)header) + sizeof(ComponentMemoryStruct) + (id*sizeof(uint64)))	/*!< Pointer to the offset slot for component @a id. */
#define GETCOMPOFFSET(header,id) *GETCOMPOFFSETP(header,id)	/*!< Offset value for component @a id (0 = not present). */
#define GETCOMPDATA(header,id) (ComponentInfoStruct*)(GETCOMPOFFSET(header,id) ? ((char*)header) + (header->indexSize * sizeof(uint64)) + GETCOMPOFFSET(header,id) : NULL)	/*!< Record pointer for component @a id, or NULL. */
/*! @} */

/*! @brief Root header of the component-memory segment.
    Followed in memory by indexSize uint64 offsets, then the packed component records.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ComponentMemoryStruct {
	uint64 size;			/*!< Total segment size in bytes. */
	uint32 cid;				/*!< Check/magic id validated on attach. */
	uint64 createdTime;		// time of creation
	uint32 indexSize;		/*!< Number of offset slots in the index. */
	uint32 count;			/*!< Number of registered components. */
	uint32 maxID;			/*!< Highest component id assigned so far. */
	uint64 usage;			/*!< Bytes currently in use in the segment. */
	// index * N, each a uint64
};

/*! @name Parameter data types (ParamHeader::type)
    @{ */
#define PARAM_STRING		1	/*!< Single string value. */
#define PARAM_INTEGER		2	/*!< int64 with default/min/max/interval (ParamIntegerHeader). */
#define PARAM_FLOAT			3	/*!< float64 with default/min/max/interval (ParamFloatHeader). */
#define PARAM_STRING_COLL	4	/*!< Collection of strings with a selected index. */
#define PARAM_INTEGER_COLL	5	/*!< Collection of int64 values with a selected index. */
#define PARAM_FLOAT_COLL	6	/*!< Collection of float64 values with a selected index. */
#define PARAM_TYPE_COLL		7	/*!< Collection of type names with a selected index. */
/*! @} */

/*! Migration-policy flag: component may be moved to another process/node. */
#define COMPONENT_CAN_MIGRATE	1

/*! @brief Per-component throughput counters and recent-message rings (in shared memory).
    @ingroup Memory
    Same ring scheme as ProcessStats: 10 DRAFTMSGSIZE-byte draft slots per direction.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ComponentStats {
	uint64 time;		/*!< Timestamp of the last update (µs). */
	uint64 msgInCount;	/*!< Total messages received. */
	uint64 msgInBytes;	/*!< Total bytes received. */
	char recentInMsg[10*DRAFTMSGSIZE];	/*!< Ring of the 10 most recent inbound message drafts. */
	uint64 msgOutCount;	/*!< Total messages posted. */
	uint64 msgOutBytes;	/*!< Total bytes posted. */
	char recentOutMsg[10*DRAFTMSGSIZE];	/*!< Ring of the 10 most recent outbound message drafts. */
	uint64 firstRunStartTime;	/*!< Timestamp of the first run (µs). */
	uint64 currentRunStartTime;	/*!< Timestamp the current/last run started (µs). */
	uint64 cycleCount;		/*!< Total processing cycles. */
	uint64 runCount;		/*!< Total runs. */
	uint32 migrationCount;	/*!< Times this component has migrated. */
	uint64 usageCPUTicks;	/*!< Cumulative CPU ticks consumed. */
	uint32 recentInPos;	 // circular write index into recentInMsg ring (newest written here, then advanced)
	uint32 recentOutPos; // circular write index into recentOutMsg ring
	/*! Serialize counters and recent messages as a \<componentstats\> XML element. @return XML fragment. */
	std::string toXML() {
		std::string xmlIn, xmlOut;
		int n;
		const char* oldData = NULL;
		DataMessage* msg = new DataMessage();
		char* msgData = recentInMsg;
		for (n = 0; n < 10; n++) {
			if (((DataMessageHeader*)msgData)->time) {
				if (!oldData) oldData = msg->swapMessageData(msgData);
				else msg->swapMessageData(msgData);
				xmlIn += msg->toXML();
			}
			msgData += DRAFTMSGSIZE;
		}
		msgData = recentOutMsg;
		for (n = 0; n < 10; n++) {
			if (((DataMessageHeader*)msgData)->time) {
				if (!oldData) oldData = msg->swapMessageData(msgData);
				else msg->swapMessageData(msgData);
				xmlOut += msg->toXML();
			}
			msgData += DRAFTMSGSIZE;
		}
		if (oldData)
			msg->swapMessageData(oldData);
		delete(msg);
		return utils::StringFormat("<componentstats runcount=\"%llu\" msgincount=\"%llu\" msginbytes=\"%llu\" msgoutcount=\"%llu\" msgoutbytes=\"%llu\" time=\"%llu\">\n<inmsg>\n%s</inmsg>\n<outmsg>\n%s</outmsg>\n</componentstats>\n",
			runCount, msgInCount, msgInBytes, msgOutCount, msgOutBytes, time, xmlIn.c_str(), xmlOut.c_str());
	}
};

/*! @name Self-trigger policy values (may a component trigger itself with its own output?)
    @{ */
#define SELFTRIGGER_NONE 0	/*!< Self-triggering forbidden. */
#define SELFTRIGGER_WARN 1	/*!< Allowed but logged as a warning. */
#define SELFTRIGGER_ALLOW 2	/*!< Explicitly allowed. */
/*! @} */


/*! @brief One component's registry record in shared memory.
    Variable-sized: the fixed fields below are followed by paramSize bytes of parameters
    (ParamHeader entries) and dataSize bytes of private data (PrivateHeader entries).
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ComponentInfoStruct {
	uint64 size;		/*!< Total record size in bytes including parameter and data areas. */
	uint32 id;			/*!< Component id (index into the segment's offset table). */
	uint8 syncStatus;	/*!< Cluster sync status (0: not there, 1: in-sync, 2: ready). */
	uint8 selfTrigger;	/*!< SELFTRIGGER_* policy. */
	uint8 type;    	/*!< Component type (Whiteboard, Catalog, Module, ...). */
	uint8 status;    	/*!< COMPSTATUS_* run status. */
	uint8 policy;		/*!< Migration policy (COMPONENT_CAN_MIGRATE flag). */
	uint16 nodeID; 		/*!< Node the component currently runs on. */
	uint16 procID; 		/*!< Process (space) the component currently runs in. */
	// Basic data
	uint64 createdTime;		/*!< Creation timestamp (µs). */
	uint64 migratedTime;	/*!< Timestamp of the last migration (µs), 0 if never migrated. */
	uint64 lastUpdateTime;	/*!< Timestamp of the last record update (µs). */
	char name[MAXKEYNAMELEN]; /*!< Component name (unique per system). */
	// Statistics
	ComponentStats stats;
	AveragePerfStats perfStats;
	// Parameters
	uint16 paramCount;
	uint32 paramSize;
	// Private Data
	uint16 dataCount;
	uint64 dataSize;

	std::string toXML(bool printStats = true) {
		if (printStats)
			return utils::StringFormat("<component id=\"%u\" status=\"%u\" name=\"%s\" node=\"%u\" proc=\"%u\" type=\"%u\" policy=\"%u\" paramcount=\"%u\" paramsize=\"%u\" datacount=\"%u\" datasize=\"%llu\" createdtime=\"%llu\" migratedtime=\"%llu\" lastupdatetime=\"%llu\" selftrigger=\"%u\">\n%s%s</component>\n",
				id, syncStatus, name, nodeID, procID, type, policy, paramCount, paramSize, dataCount, dataSize, createdTime, migratedTime, lastUpdateTime, selfTrigger, stats.toXML().c_str(), perfStats.toXML().c_str());
		else
			return utils::StringFormat("<component id=\"%u\" status=\"%u\" name=\"%s\" node=\"%u\" proc=\"%u\" type=\"%u\" policy=\"%u\" paramcount=\"%u\" paramsize=\"%u\" datacount=\"%u\" datasize=\"%llu\" createdtime=\"%llu\" migratedtime=\"%llu\" lastupdatetime=\"%llu\" selftrigger=\"%u\" />\n",
				id, syncStatus, name, nodeID, procID, type, policy, paramCount, paramSize, dataCount, dataSize, createdTime, migratedTime, lastUpdateTime, selfTrigger);
	}
	bool writeToMsg(uint32 n, DataMessage* msg) {
		if (!msg) return false;
		msg->setInt((int64)n, "ID", id);
		msg->setInt((int64)n, "Status", status);
		msg->setInt((int64)n, "Type", type);
		msg->setInt((int64)n, "Policy", policy);
		msg->setInt((int64)n, "SelfTrigger", selfTrigger);
		msg->setInt((int64)n, "Size", size);
		msg->setInt((int64)n, "NodeID", nodeID);
		msg->setInt((int64)n, "ProcID", procID);
		msg->setString((int64)n, "Name", name);
		msg->setTime((int64)n, "CreatedTime", createdTime);
		return true;
	}
};

/*! Total bytes used by a component record including its parameter and private-data areas. */
#define COMPINFOUSAGE(info) (sizeof(ComponentInfoStruct) + info->paramSize + info->dataSize)

/*! @brief Size-prefixed private-data entry stored after a component record.
    Layout after the header: name, NUL, mimetype, NUL, raw data bytes.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct PrivateHeader {
	uint64 size;	/*!< Total entry size in bytes including this header. */
	// name, 0, mimetype, 0, data
};

/*! @brief Size- and type-prefixed parameter entry stored after a component record.
    Layout after the header: name, NUL, then the type-specific struct
    (ParamIntegerHeader / ParamFloatHeader / ParamCollectionHeader / string bytes).
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ParamHeader {
	uint32 size;	/*!< Total entry size in bytes including this header. */
	uint8 type;		/*!< PARAM_* data type. */
	// name, 0, struct
};

// -- integer --
/*! @brief Value block of a PARAM_INTEGER parameter.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ParamIntegerHeader {
	int64 val;			/*!< Current value. */
	int64 defaultVal;	/*!< Value restored by resetParameter(). */
	int64 minVal;		/*!< Inclusive lower bound (0 = unbounded when max also 0). */
	int64 maxVal;		/*!< Inclusive upper bound. */
	int64 interval;		/*!< Step used by tweakParameter(). */
};

// -- float --
/*! @brief Value block of a PARAM_FLOAT parameter.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ParamFloatHeader {
	float64 val;		/*!< Current value. */
	float64 defaultVal;	/*!< Value restored by resetParameter(). */
	float64 minVal;		/*!< Inclusive lower bound. */
	float64 maxVal;		/*!< Inclusive upper bound. */
	float64 interval;	/*!< Step used by tweakParameter(). */
};

// -- integer collection --
/*! @brief Value block of a PARAM_*_COLL parameter; followed by the packed collection values.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct ParamCollectionHeader {
	uint32 index;		/*!< Currently selected entry. */
	uint32 defaultIndex;/*!< Entry restored by resetParameter(). */
	uint32 count;		/*!< Number of entries in the collection. */
};

/*! Re-open the component segment if the master's resize serial no longer matches ours;
    bails out of the calling method (returning 0) on failure. */
#define CHECKCOMPONENTMEMORYSERIAL 	if (serial != master->getComponentShmemSerial()) {if (!open()) {mutex->leave();return 0;}}
#define CHECKCOMPONENTMEMORYSERIALRETURN(a) 	if (serial != master->getComponentShmemSerial()) {if (!open()) {mutex->leave();return a;}}

class MasterMemory;
/*! @brief Accessor for the shared component registry.
    @ingroup Memory
    One instance per process (created by MemoryManager). The node master calls create();
    other processes open(). Every method locks the segment's named cross-process mutex and
    re-attaches when the segment was resized elsewhere (serial check). String/char* out
    parameters are copied into caller buffers; returned containers (vectors/lists) are
    heap-allocated and owned by the caller. The @a master pointer is borrowed.
    @code
    uint32 cid; uint32 existing;
    componentMemory->createComponent(cid, type, policy, SELFTRIGGER_NONE,
                                     "MyModule", 4096, nodeID, procID, now, existing);
    componentMemory->createParameter(cid, "Threshold", (int64)10, 0, 100, 1);
    int64 v = componentMemory->getParameterInt(cid, "Threshold");
    @endcode */
class ComponentMemory {
public:
	static bool UnitTest();	/*!< Self-test. @return true if all checks pass. */

	/*! @param master Segment bookkeeping interface (borrowed, not owned). */
	ComponentMemory(MasterMemory* master);
	~ComponentMemory();

	/*! Report allocation/usage of the component segment. @return true on success. */
	bool getMemoryUsage(uint64& alloc, uint64& usage);

	bool open();	/*!< Attach to the existing component segment. @return true on success. */
	/*! Create the component segment (master only). @param indexSize Component-id capacity. @return true on success. */
	bool create(uint32 indexSize);

	std::vector<ComponentInfoStruct>* getAllComponents();			/*!< Snapshot all components. @return Caller-owned vector. */
	std::vector<ComponentInfoStruct>* getAllLocalComponents();		/*!< Snapshot components on this node. @return Caller-owned vector. */
	std::vector<ComponentInfoStruct>* getAllLocalComponents(uint8 type);	/*!< Snapshot local components of @a type. @return Caller-owned vector. */
	std::vector<ComponentInfoStruct>* getAllModules();				/*!< Snapshot all module components. @return Caller-owned vector. */
	std::vector<ComponentInfoStruct>* getAllCatalogs();				/*!< Snapshot all catalog components. @return Caller-owned vector. */

	bool writeComponentsToMsg(DataMessage* msg);		/*!< Serialize all component records into @a msg. @return true on success. */
	bool writeComponentNamesToMsg(DataMessage* msg);	/*!< Write just the component names into @a msg. @return true on success. */
	bool syncComponents(DataMessage* msg);				/*!< Merge component records received from a remote node. @return true on success. */

	bool confirmComponentID(uint32 id);	/*!< Mark a provisionally reserved component id as ready (syncStatus 2). @return true on success. */
	bool cancelComponentID(uint32 id);	/*!< Release a provisionally reserved component id. @return true on success. */
	/*! Look up a component by name without filtering on readiness.
	    @param name Component name to look up.
	    @param id Receives the component id when found.
	    @return Sync status: 0 not there, 1 in-sync (reserved), 2 ready. */
	uint8 lookupComponentID(const char* name, uint32 &id); // status = 0: not there, 1: in-sync, 2: ready
	/*! Register a component record.
	    @param id Requested component id. @param type Component type. @param policy Migration policy.
	    @param selfTrigger SELFTRIGGER_* policy. @param name Unique component name.
	    @param size Initial record size in bytes. @param nodeID Node the component lives on. @param procID Process the component lives in.
	    @param time Creation timestamp (µs). @param existingID Receives the id of a
	    pre-existing component with the same name, if any. @return true on success. */
	bool createComponent(uint32 id, uint8 type, uint8 policy, uint8 selfTrigger, const char* name, uint64 size, uint16 nodeID, uint16 procID, uint64 time, uint32& existingID);
//	bool recordRemoteComponent(uint32 id, const char* name, uint16 nodeID, uint64 time);
//	bool reserveComponentID(uint32 id, const char* name);
	bool destroyComponent(uint32 cid);	/*!< Remove a component record and free its space. @return true on success. */
	bool getComponentName(uint32 cid, char* name, uint32 maxNameLen);	/*!< Copy the component name into @a name. @return true if found. */
	std::string getComponentNameString(uint32 cid);		/*!< @return Component name, or empty string if unknown. */
	uint8 getComponentType(uint32 cid);					/*!< @return Component type, 0 if unknown. */
	bool getComponentID(const char* name, uint32 &cid);	/*!< Look up a component id by name. @return true if found. */
	ComponentStats getComponentStats(uint32 cid);		/*!< @return Copy of the component's stats (zeroed if unknown). */
	bool setComponentStats(uint32 cid, ComponentStats& stats);	/*!< Overwrite the component's stats. @return true on success. */
	AveragePerfStats getComponentPerfStats(uint32 cid);	/*!< @return Copy of the windowed performance averages. */
	bool setComponentPerfStats(uint32 cid, AveragePerfStats &perfStruct);	/*!< Store new performance averages. @return true on success. */

	bool isComponentLocal(uint32 cid);			/*!< @return true if the component runs on this node. */
	bool isComponentLocal(const char* name);	/*!< @return true if the named component runs on this node. */
	bool getComponentLocation(uint32 cid, uint16& nodeID, uint16& procID);	/*!< Get the node/process the component runs in. @return true if found. */
	uint8 getComponentPolicy(uint32 cid);		/*!< @return Migration policy, 0 if unknown. */
	/*! Update type/policy/self-trigger/location in one call. @return true on success. */
	bool updateComponentInformation(uint32 cid, uint8 type, uint8 policy, uint8 selfTrigger, uint16 nodeID, uint16 procID);
	bool setComponentPolicy(uint32 cid, uint8 policy);			/*!< Set the migration policy. @return true on success. */
	uint8 getComponentSelfTrigger(uint32 cid);					/*!< @return SELFTRIGGER_* policy. */
	bool setComponentSelfTrigger(uint32 cid, uint8 selfTrigger);/*!< Set the self-trigger policy. @return true on success. */
	uint16 getComponentNodeID(uint32 cid);		/*!< @return Node id hosting the component. */
	uint16 getComponentProcessID(uint32 cid);	/*!< @return Process id hosting the component. */
	bool updateComponentLocation(uint32 cid, uint16 nodeID, uint16 procID);	/*!< Record a new location (after migration). @return true on success. */
	// char* GetAndRemoveComponent(uint32 cid, uint32& dataSize);
	// bool addExistingComponent(uint32 cid, uint16 nodeID, uint16 procID, char* oldData, uint32 dataSize);
	// bool updateRemoteComponent(uint32 cid, uint16 nodeID, uint16 procID, const char* name);
	/*! Fold a run's activity into the component's stats (counters, rings, CPU ticks).
	    Caller keeps ownership of both messages. @return true on success. */
	bool addComponentStats(uint32 cid, uint8 status, uint64 usageCPUTicks,
		DataMessage* inputMsg, DataMessage* outputMsg, uint32 runCount, uint32 cycleCount);

	bool canComponentMigrate(uint32 cid);	/*!< @return true if the component's policy allows migration. */
	std::list<uint16>* findProcessComponents(uint16 procID);	/*!< List ids of components in process @a procID. @return Caller-owned list. */

	/*! Copy a component's whole data area (for migration). @param cid Component id. @param size Receives byte count.
	    @return Caller-owned heap buffer (free with free()/delete[] per implementation), or NULL. */
	char* getComponentData(uint32 cid, uint64& size);
	/*! Replace a component's data area (after migration). @param cid Component id. @param data New data area. @param size Byte count. @param wasMigrated Marks a migration event. @return true on success. */
	bool setComponentData(uint32 cid, const char* data, uint64 size, bool wasMigrated);

	// Private Data
	/*! @name Private data (named binary blobs owned by a component)
	    Blobs are stored inline in the component record with optional mimetype.
	    @{ */
	bool setPrivateData(uint32 cid, const char* name, const char* data, uint64 size, const char* mimetype = NULL);	/*!< Create/replace blob @a name. Data is copied. @return true on success. */
	uint64 getPrivateDataSize(uint32 cid, const char* name);			/*!< @return Blob size in bytes, 0 if absent. */
	std::string getPrivateDataMimetype(uint32 cid, const char* name);	/*!< @return Blob mimetype, empty if absent. */
	bool getPrivateData(uint32 cid, const char* name, char* data, uint64 maxSize);	/*!< Copy blob into caller buffer @a data (max @a maxSize). @return true on success. */
	char* getPrivateDataCopy(uint32 cid, const char* name, uint64 &size);	/*!< @return Caller-owned heap copy of the blob, or NULL. */
	bool deletePrivateData(uint32 cid, const char* name);					/*!< Delete blob @a name. @return true on success. */
	std::map<std::string, std::string> getPrivateDataKeysAndTypes(uint32 cid);	/*!< @return Map of blob name to mimetype. */
	std::list<std::string> getPrivateDataKeys(uint32 cid);					/*!< @return List of blob names. */
	/*! @} */

	// Parameters
	/*! @name Parameter creation
	    Overloads create string/integer/float parameters or collections thereof; values are
	    copied into the component record. min/max/interval of 0 mean unconstrained.
	    @return true on success (false if the parameter exists with a different type).
	    @{ */
	bool createParameter(uint32 cid, const char* name, const char* val, const char* defaultValue = NULL);
	bool createParameter(uint32 cid, const char* name, const char* val, uint32 count, uint32 defaultIndex);
	bool createParameter(uint32 cid, const char* name, std::vector<std::string> values, const char* defaultValue = NULL);
	bool createParameter(uint32 cid, const char* name, int64* val, uint32 count, uint32 defaultIndex);
	bool createParameter(uint32 cid, const char* name, std::vector<std::string> values, int64 defaultValue);
	bool createParameter(uint32 cid, const char* name, std::vector<int64> values, int64 defaultValue = 0);
	bool createParameter(uint32 cid, const char* name, float64* val, uint32 count, uint32 defaultIndex);
	bool createParameter(uint32 cid, const char* name, std::vector<std::string> values, float64 defaultValue);
	bool createParameter(uint32 cid, const char* name, std::vector<float64> values, float64 defaultValue = 0);
	bool createParameter(uint32 cid, const char* name, int64 val, int64 min = 0, int64 max = 0, int64 interval = 0);
	bool createParameter(uint32 cid, const char* name, float64 val, float64 min = 0, float64 max = 0, float64 interval = 0);
	/*! @} */

	bool hasParameter(uint32 cid, const char* name);	/*!< @return true if the parameter exists. */
	bool deleteParameter(uint32 cid, const char* name);	/*!< Remove the parameter. @return true on success. */

	/*! @name Parameter access
	    Typed getters convert where sensible; getters return 0/empty on missing parameters.
	    Setters clamp to min/max where configured. @return true on success (bool forms).
	    @{ */
	uint8 getParameterDataType(uint32 cid, const char* name);	/*!< @return PARAM_* type, 0 if absent. */
	uint32 getParameterValueSize(uint32 cid, const char* name);	/*!< @return Byte size of the current value. */
	bool getParameter(uint32 cid, const char* name, char* val, uint32 maxSize);
	bool getParameter(uint32 cid, const char* name, int64& val);
	bool getParameter(uint32 cid, const char* name, float64& val);
	std::string getParameterString(uint32 cid, const char* name, uint32 maxSize);
	std::string getParameterString(uint32 cid, const char* name);
	int64 getParameterInt(uint32 cid, const char* name);
	float64 getParameterFloat(uint32 cid, const char* name);
	bool getParameterAsBool(uint32 cid, const char* name);

	bool setParameter(uint32 cid, const char* name, const char* val);
	bool setParameter(uint32 cid, const char* name, int64 val);
	bool setParameter(uint32 cid, const char* name, float64 val);

	bool resetParameter(uint32 cid, const char* name);				/*!< Restore the parameter's default value/index. @return true on success. */
	bool tweakParameter(uint32 cid, const char* name, int32 tweak);	/*!< Step the value by @a tweak * interval (or collection index). @return true on success. */
	/*! @} */

	bool addLocalPerformanceStats(std::list<PerfStats> &perfStats);	/*!< Append PerfStats for all local components. @return true on success. */
	std::string printFriendly();			/*!< @return Human-readable dump of the registry. */
	std::string toXML(bool stats = true);	/*!< @return XML dump of all components (optionally with stats). */

private:
	bool resize(uint64 newMemorySize);
	bool resizeIndex(uint32 newIndexSize);
	bool resizeComponent(uint32 id, uint64 newSize);
	bool growComponent(uint32 id, uint64 addSize);
	bool getSurroundingComponents(uint32 cid, uint32& prevID, uint32& nextID);

	char* makeRoomForPrivateData(uint32 cid, uint64 newSize);
	char* makeRoomForParameter(uint32 cid, uint64 newSize);

	ParamHeader* getParameter(uint32 cid, const char* name);
	PrivateHeader* getPrivateData(uint32 cid, const char* name);

	utils::Mutex* mutex;			/*!< Named cross-process mutex guarding the segment (owned). */
	MasterMemory* master;			/*!< Bookkeeping interface for size/serial (borrowed). */
	ComponentMemoryStruct* header;	/*!< Mapped segment header (owned by the OS). */
	uint64 memorySize;				/*!< Size of our current mapping in bytes. */
	uint16 port;					/*!< Node port used in segment naming. */
	uint32 serial;					/*!< Cached resize serial; mismatch triggers re-open. */
};

} // namespace cmlabs

#endif //_COMPONENTMEMORY_H_

