| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- // ================================================================================
- // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
- // == See tb_core.h for more information. ==
- // ================================================================================
- #include "tb_node_ref_tree.h"
- #include "tb_language.h"
- #include "tb_system.h"
- namespace tb {
- // == TBNodeRefTree ==============================================================
- //static
- TBLinkListOf<TBNodeRefTree> TBNodeRefTree::s_ref_trees;
- TBNodeRefTree::TBNodeRefTree(const char *name) : m_name(name), m_name_id(name)
- {
- s_ref_trees.AddLast(this);
- }
- TBNodeRefTree::~TBNodeRefTree()
- {
- s_ref_trees.Remove(this);
- }
- TBValue &TBNodeRefTree::GetValue(const char *request)
- {
- if (TBNode *node = m_node.GetNodeFollowRef(request))
- return node->GetValue();
- TBDebugPrint("TBNodeRefTree::GetValue - Request not found: %s\n", request);
- static TBValue nullval;
- return nullval;
- }
- //static
- TBValue &TBNodeRefTree::GetValueFromTree(const char *request)
- {
- assert(*request == '@');
- TBNode tmp;
- tmp.GetValue().SetString(request, TBValue::SET_AS_STATIC);
- TBNode *node = TBNodeRefTree::FollowNodeRef(&tmp);
- if (node != &tmp)
- return node->GetValue();
- static TBValue nullval;
- return nullval;
- }
- void TBNodeRefTree::SetValue(const char *request, const TBValue &value)
- {
- if (TBNode *node = m_node.GetNode(request, TBNode::GET_MISS_POLICY_CREATE))
- {
- // FIX: Only invoke the listener if it really changed.
- node->GetValue().Copy(value);
- InvokeChangeListenersInternal(request);
- }
- }
- void TBNodeRefTree::InvokeChangeListenersInternal(const char *request)
- {
- TBLinkListOf<TBNodeRefTreeListener>::Iterator iter = m_listeners.IterateForward();
- while (TBNodeRefTreeListener *listener = iter.GetAndStep())
- listener->OnDataChanged(this, request);
- }
- //static
- TBNodeRefTree *TBNodeRefTree::GetRefTree(const char *name, int name_len)
- {
- for (TBNodeRefTree *rt = s_ref_trees.GetFirst(); rt; rt = rt->GetNext())
- if (strncmp(rt->GetName(), name, name_len) == 0)
- return rt;
- return nullptr;
- }
- //static
- TBNode *TBNodeRefTree::FollowNodeRef(TBNode *node)
- {
- // Detect circular loops by letting this call get a unique id.
- // Update the id on each visited node and if it's already set,
- // there's a loop. This cost the storage of id in each TBNode,
- // and assumes the look up doesn't cause other lookups
- // recursively.
- // FIX: Switch to hare and teleporting tortouise?
- static uint32 s_cycle_id = 0;
- uint32 cycle_id = ++s_cycle_id;
- TBNode *start_node = node;
- while (node->GetValue().IsString())
- {
- // If not a reference at all, we're done.
- const char *node_str = node->GetValue().GetString();
- if (*node_str != '@')
- break;
- // If there's no tree name and request, we're done. It's probably a language string.
- const char *name_start = node_str + 1;
- const char *name_end = TBNode::GetNextNodeSeparator(name_start);
- if (*name_end == 0)
- break;
- // We have a "@treename>noderequest" string. Go ahead and look it up.
- if (TBNodeRefTree *rt = TBNodeRefTree::GetRefTree(name_start, name_end - name_start))
- {
- TBNode *next_node = rt->m_node.GetNode(name_end + 1, TBNode::GET_MISS_POLICY_NULL);
- if (!next_node)
- {
- TBDebugPrint("TBNodeRefTree::ResolveNode - Node not found on request \"%s\"\n", node_str);
- break;
- }
- node = next_node;
- // Detect circular reference loop.
- if (node->m_cycle_id != cycle_id)
- node->m_cycle_id = cycle_id;
- else
- {
- TBDebugPrint("TBNodeRefTree::ResolveNode - Reference loop detected on request \"%s\" from node \"%s\"\n",
- node_str, node->GetValue().GetString());
- return start_node;
- }
- }
- else
- {
- TBDebugPrint("TBNodeRefTree::ResolveNode - No tree found for request \"%s\" from node \"%s\"\n",
- node_str, node->GetValue().GetString());
- break;
- }
- }
- return node;
- }
- //static
- void TBNodeRefTree::ResolveConditions(TBNode *parent_node)
- {
- bool condition_ret = false;
- TBNode *node = parent_node->GetFirstChild();
- while (node)
- {
- bool delete_node = false;
- bool move_children = false;
- if (strcmp(node->GetName(), "@if") == 0)
- {
- condition_ret = node->GetValueFollowRef().GetInt() ? true : false;
- if (condition_ret)
- move_children = true;
- delete_node = true;
- }
- else if (strcmp(node->GetName(), "@else") == 0)
- {
- condition_ret = !condition_ret;
- if (condition_ret)
- move_children = true;
- delete_node = true;
- }
- // Make sure we'll skip any nodes added from a conditional branch.
- TBNode *node_next = node->GetNext();
- if (move_children)
- {
- // Resolve the branch first, since we'll skip it.
- ResolveConditions(node);
- while (TBNode *content = node->GetLastChild())
- {
- node->Remove(content);
- parent_node->AddAfter(content, node);
- }
- }
- if (delete_node)
- parent_node->Delete(node);
- else
- ResolveConditions(node);
- node = node_next;
- }
- }
- }; // namespace tb
|