diff --git a/Data/FlagSet.hs b/Data/FlagSet.hs
new file mode 100644
--- /dev/null
+++ b/Data/FlagSet.hs
@@ -0,0 +1,173 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+-- | 
+-- = Introduction
+-- This module provides a data type for a set of flags. Flags are stored
+-- efficiently as bits of an unsigned integer.
+--
+-- This module is meant to be imported qualified:
+--
+-- @
+-- import qualified Data.FlagSet as FlagSet
+-- import Data.FlagSet (FlagSet)
+-- @
+--
+-- The API is basically the same as that of "Data.Set" from the @containers@ package.
+--
+-- The functions `fromList` and `member` also have aliases that can be used 
+-- unqualified:
+-- 
+-- @
+-- import Data.FlagSet (flags, hasFlag)
+-- @
+--
+-- = Examples
+--
+-- @
+-- import qualified Data.FlagSet as FlagSet
+-- import Data.FlagSet (FlagSet, flags, hasFlag)
+--
+-- data WeekDay = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
+--      deriving (Eq, Show, Enum, Bounded)
+--
+-- workDays = flags [Monday .. Friday]
+-- weekEndDays = flags [Saturday, Sunday]
+-- allDays = FlagSet.full
+--
+-- worksOnTheWeekEnd :: FlagSet WeekDay -> Bool
+-- worksOnTheWeekEnd = not . FlagSet.null . FlagSet.intersection weekEndDays
+--
+-- worksOnSunday :: FlagSet WeekDay -> Bool
+-- worksOnSunday = hasFlag Sunday
+--
+-- workDayPay :: Rational
+-- workDayPay = ...
+-- weekEndDayPay :: Rational
+-- weekEndDayPay = ...
+--
+-- pay :: FlagSet WeekDay -> Rational
+-- pay daysWorking = workDayPay * countDays workDays + weekEndDayPay * countDays weekEndDays
+--     where
+--         countDays = fromIntegral . FlagSet.size . FlagSet.intersection daysWorking
+-- @
+module Data.FlagSet
+    ( -- * Types
+      FlagSet
+      -- * Construction
+    , fromList, flags, empty, singleton, full
+      -- * Modification
+    , insert, delete, union, unions, difference, intersection
+      -- * Tests
+    , member, hasFlag, null
+      -- * Other
+    , toList, size
+    ) where
+
+import Data.Data (Data)
+import Data.Typeable (Typeable)
+import Data.Word (Word32)
+import Data.Bits (setBit, testBit, clearBit, (.|.), (.&.), complement, popCount)
+import Data.Monoid (Monoid(..))
+import Prelude hiding (null)
+
+-- | A set of flags.
+--
+--   For most functions operating on flag sets, there must be an `Enum`
+--   instance for @a@. Some functions also require `Bounded`.
+--
+--   You must ensure that `fromEnum` only returns values in the range
+--   @[0 .. 31]@, otherwise an error can occur.
+-- 
+--   In the `Monoid` instance, `mempty` is `empty` and `mappend`/`<>` is `union`.
+newtype FlagSet a = MkFlagSet Word32 deriving (Data, Typeable)
+
+instance Eq (FlagSet a) where
+    MkFlagSet x == MkFlagSet y = x == y
+
+instance Ord (FlagSet a) where
+    compare (MkFlagSet x) (MkFlagSet y) = compare x y
+
+instance (Show a, Enum a) => Show (FlagSet a) where
+    showsPrec p fs = showParen (p > 10) $
+        showString "fromList " . shows (toList fs)
+
+instance Monoid (FlagSet a) where
+    mempty = empty
+    mappend = union
+
+-- | Alias for `fromList` that can be imported unqualified.
+flags :: Enum a => [a] -> FlagSet a
+flags = fromList
+
+-- | Alias for `member` that can be imported unqualified.
+hasFlag :: Enum a => a -> FlagSet a -> Bool
+hasFlag = member
+
+-- | Create a flag set from a list of flags. Input list can contain duplicates.
+fromList :: Enum a => [a] -> FlagSet a
+fromList vals = go vals 0
+    where
+        go [] acc = MkFlagSet acc
+        go (v:vs) acc = withBit "fromList" v (go vs . setBit acc)
+
+-- | Test whether a flag set contains a value.
+member :: Enum a => a -> FlagSet a -> Bool
+member v (MkFlagSet bits) = withBit "member" v (testBit bits)
+
+withBit :: Enum a => String -> a -> (Int -> b) -> b
+withBit fun v cont =
+    let
+        n = fromEnum v
+    in
+        if n < 0 || n > 31
+            then error $ "Data.FlagSet." ++ fun ++ ": enum out of range"
+            else cont n
+
+-- | Convert a flag set to a list of values. The values will be ordered
+--   according to the order defined by `fromEnum` and there will not be any
+--   duplicates.
+toList :: Enum a => FlagSet a -> [a]
+toList (MkFlagSet bits) = map toEnum $ filter (testBit bits) [0 .. 31]
+
+-- | The empty flag set.
+empty :: FlagSet a
+empty = MkFlagSet 0
+
+-- | A flag set containing a single value.
+singleton :: Enum a => a -> FlagSet a
+singleton v = withBit "singleton" v (MkFlagSet . setBit 0)
+
+-- | The union of two flag sets.
+union :: FlagSet a -> FlagSet a -> FlagSet a
+union (MkFlagSet x) (MkFlagSet y) = MkFlagSet (x .|. y)
+
+-- | The union of multiple flag sets.
+unions :: [FlagSet a] -> FlagSet a
+unions = foldl union empty
+
+-- | The difference of two flag sets.
+difference :: FlagSet a -> FlagSet a -> FlagSet a
+difference (MkFlagSet x) (MkFlagSet y) = MkFlagSet (x .&. complement y)
+
+-- | The intersection of two flag sets.
+intersection :: FlagSet a -> FlagSet a -> FlagSet a
+intersection (MkFlagSet x) (MkFlagSet y) = MkFlagSet (x .&. y)
+
+-- | The flag set that contains every value.
+full :: (Enum a, Bounded a) => FlagSet a
+full = fromList [minBound .. maxBound]
+
+-- | Insert a value into a flag set.
+insert :: Enum a => a -> FlagSet a -> FlagSet a
+insert v (MkFlagSet bits) = withBit "insert" v (MkFlagSet . setBit bits)
+
+-- | Remove a value from a flag set.
+delete :: Enum a => a -> FlagSet a -> FlagSet a
+delete v (MkFlagSet bits) = withBit "delete" v (MkFlagSet . clearBit bits)
+
+-- | Test whether a flag set is empty.
+null :: FlagSet a -> Bool
+null = (== empty)
+
+-- | The number of values in a flag set.
+size :: FlagSet a -> Int
+size (MkFlagSet bits) = popCount bits
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015 Tobias Brandt
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/data-flagset.cabal b/data-flagset.cabal
new file mode 100644
--- /dev/null
+++ b/data-flagset.cabal
@@ -0,0 +1,72 @@
+-- Initial data-flagset.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                data-flagset
+
+-- The package version.  See the Haskell package versioning policy (PVP) 
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             1.0.0.0
+
+-- A short (one-line) description of the package.
+synopsis:            An efficient data type for sets of flags
+
+-- A longer description of the package.
+description:         This package provides a data type for representing a set of
+                     enum flags with an API similar to that of Data.Set from
+                     the containers package.
+
+-- The license under which the package is released.
+license:             MIT
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Tobias Brandt
+
+-- An email address to which users can send suggestions, bug reports, and 
+-- patches.
+maintainer:          tob.brandt@gmail.com
+
+-- A copyright notice.
+copyright:           Copyright 2015, Tobias Brandt
+
+category:            Data
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a 
+-- README.
+-- extra-source-files:  
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules:   Data.FlagSet
+  
+  -- Modules included in this library but not exported.
+  -- other-modules:       
+  
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:    
+  
+  -- Other library packages from which modules are imported.
+  build-depends:       base >=4.5 && <4.9
+  
+  -- Directories containing source files.
+  -- hs-source-dirs:      
+  
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+  
+source-repository head
+    type: git
+    location: git://github.com/TobBrandt/data-flagset.git
