File: eclass.h

package info (click to toggle)
darkradiant 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 41,080 kB
  • sloc: cpp: 264,743; ansic: 10,659; python: 1,852; xml: 1,650; sh: 92; makefile: 21
file content (137 lines) | stat: -rw-r--r-- 3,613 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
 * \file
 * Helper functions for dealing with IEntityClass and related objects.
 */
#pragma once

#include "ieclass.h"

#include <vector>

#include <functional>
#include "string/predicate.h"

namespace eclass
{

typedef std::vector<EntityClassAttribute> AttributeList;

namespace detail
{
    class AttributeSuffixComparator
    {
        // Starting position to convert to a number
        std::size_t _startPos;

    public:

        /// Constructor. Initialise the start position.
        AttributeSuffixComparator(std::size_t startPos)
        : _startPos(startPos)
        { }

        bool operator() (const EntityClassAttribute& x,
                         const EntityClassAttribute& y) const
        {
            // Get both substrings. An empty suffix comes first.
            std::string sx = x.getName().substr(_startPos);
            std::string sy = y.getName().substr(_startPos);
            if (sx.empty())
                return true;
            else if (sy.empty())
                return false;

            // Try numeric sort first, then fall back to lexicographic if the
            // prefixes are not integers.
            try
            {
                int ix = std::stoi(sx);
                int iy = std::stoi(sy);

                // Perform the comparison and return
                return ix < iy;
            }
            catch (std::logic_error&)
            {
                // greebo: Non-numeric operands, use ordinary string comparison
                return sx < sy;
            }
        }
    };
}

/**
 * \brief
 * Return a list of all class spawnargs matching the given prefix.
 *
 * The list is sorted by the numeric or lexicographic ordering of the suffixes.
 * This ensures that "editor_usage1", "editor_usage2" etc are returned in the
 * correct order.
 *
 * \param eclass
 * Entity class object to search
 *
 * \param prefix
 * String prefix for the spawnargs of interest
 *
 * \param includeInherited
 * Whether to include class spawnargs inherited from the parent class. Defaults
 * to true.
 */
inline AttributeList getSpawnargsWithPrefix(const IEntityClassPtr& eclass,
                                            const std::string& prefix,
                                            bool includeInherited = true)
{
    // Populate the list with with matching attributes
    AttributeList matches;
    eclass->forEachAttribute(
        [&](const EntityClassAttribute& a, bool inherited) {
            if (string::istarts_with(a.getName(), prefix) &&
                (includeInherited || !inherited))
            {
                matches.push_back(a);
            }
        },
        true // include editor_keys
    );

    // Sort the list in suffix order before returning
    detail::AttributeSuffixComparator comp(prefix.length());
    std::sort(matches.begin(), matches.end(), comp);

    return matches;
}

/**
 * \brief
 * Get the usage text for an entity class.
 *
 * The usage text consists of the values of all "editor_usage" spawnargs
 * concatenated in order.
 */
inline std::string getUsage(const IEntityClassPtr& entityClass)
{
    // Find all relevant spawnargs in order
    AttributeList usageAttrs = getSpawnargsWithPrefix(
        entityClass, "editor_usage", false
    );

    // Build the string
    std::ostringstream usage;
    bool firstLine = true;
    for (const EntityClassAttribute& a : usageAttrs)
    {
        if (firstLine)
        {
            usage << a.getValue();
            firstLine = false;
        }
        else
        {
            usage << '\n' << a.getValue();
        }
    }
    return usage.str();
}

}